home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / sbin / firehol < prev    next >
Text File  |  2005-10-18  |  174KB  |  6,413 lines

  1. #!/bin/bash
  2. #
  3. # Startup script to implement /etc/firehol/firehol.conf pre-defined rules.
  4. #
  5. # chkconfig: 2345 99 92
  6. #
  7. # description: creates stateful iptables packet filtering firewalls.
  8. #
  9. # by Costa Tsaousis <costa@tsaousis.gr>
  10. #
  11. # config: /etc/firehol/firehol.conf
  12. #
  13. # $Id: firehol.sh,v 1.226 2005/01/25 21:28:19 ktsaou Exp $
  14. #
  15.  
  16. # Make sure only root can run us.
  17. if [ ! "${UID}" = 0 ]
  18. then
  19.     echo >&2
  20.     echo >&2
  21.     echo >&2 "Only user root can run FireHOL."
  22.     echo >&2
  23. fi
  24.  
  25. # Remember who you are.
  26. FIREHOL_FILE="${0}"
  27. FIREHOL_DEFAULT_WORKING_DIRECTORY="${PWD}"
  28.  
  29. # ------------------------------------------------------------------------------
  30. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  31. # ------------------------------------------------------------------------------
  32. #
  33. # EXTERNAL/SYSTEM COMMANDS MANAGEMENT
  34. #
  35. # ------------------------------------------------------------------------------
  36. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  37. # ------------------------------------------------------------------------------
  38.  
  39. export PATH="${PATH}:/bin:/usr/bin:/sbin:/usr/sbin"
  40.  
  41. # External commands FireHOL will need.
  42. # If one of those is not found, FireHOL will refuse to run.
  43.  
  44. which_cmd() {
  45.     local block=1
  46.     if [ "a${1}" = "a-n" ]
  47.     then
  48.         local block=0
  49.         shift
  50.     fi
  51.     
  52.     unalias $2 >/dev/null 2>&1
  53.     local cmd=`which $2 2>/dev/null | head -n 1`
  54.     if [ $? -gt 0 -o ! -x "${cmd}" ]
  55.     then
  56.         if [ ${block} -eq 1 ]
  57.         then
  58.             echo >&2
  59.             echo >&2 "ERROR:    Command '$2' not found in the system path."
  60.             echo >&2 "    FireHOL requires this command for its operation."
  61.             echo >&2 "    Please install the required package and retry."
  62.             echo >&2
  63.             echo >&2 "    Note that you need an operational 'which' command"
  64.             echo >&2 "    for FireHOL to find all the external programs it"
  65.             echo >&2 "    needs. Check it yourself. Run:"
  66.             echo >&2
  67.             echo >&2 "    which $2"
  68.             exit 1
  69.         fi
  70.         return 1
  71.     fi
  72.     
  73.     eval $1=${cmd}
  74.     return 0
  75. }
  76.  
  77. # Check for a command during runtime.
  78. # Currently the following commands are required only when needed:
  79. #
  80. # wget or curl (either is fine)
  81. # gzcat
  82. #
  83. require_cmd() {
  84.     for x in $1
  85.     do
  86.         eval var=`echo ${x} | tr 'a-z' 'A-Z'`_CMD
  87.         eval val=\$\{${var}\}
  88.         if [ -z "${val}" ]
  89.         then
  90.             which_cmd -n "${var}" "${x}"
  91.             test $? -eq 0 && return 0
  92.         fi
  93.     done
  94.     
  95.     return 1
  96. }
  97.  
  98. which_cmd CAT_CMD cat
  99. which_cmd CUT_CMD cut
  100. which_cmd CHOWN_CMD chown
  101. which_cmd CHMOD_CMD chmod
  102. which_cmd DATE_CMD date
  103. which_cmd EGREP_CMD egrep
  104. which_cmd EXPR_CMD expr
  105. which_cmd GAWK_CMD gawk
  106. which_cmd GREP_CMD grep
  107. which_cmd HEAD_CMD head
  108. which_cmd HOSTNAME_CMD hostname
  109. which_cmd IP_CMD ip
  110. which_cmd IPTABLES_CMD iptables
  111. which_cmd IPTABLES_SAVE_CMD iptables-save
  112. which_cmd LESS_CMD less
  113. which_cmd LSMOD_CMD lsmod
  114. which_cmd MKDIR_CMD mkdir
  115. which_cmd MV_CMD mv
  116. which_cmd MODPROBE_CMD modprobe
  117. which_cmd NETSTAT_CMD netstat
  118. which_cmd RENICE_CMD renice
  119. which_cmd RM_CMD rm
  120. which_cmd SED_CMD sed
  121. which_cmd SORT_CMD sort
  122. which_cmd SYSCTL_CMD sysctl
  123. which_cmd TOUCH_CMD touch
  124. which_cmd TR_CMD tr
  125. which_cmd UNAME_CMD uname
  126. which_cmd UNIQ_CMD uniq
  127.  
  128. # Make sure our generated files cannot be accessed by anyone else.
  129. umask 077
  130.  
  131. # Be nice on production environments
  132. ${RENICE_CMD} 10 $$ >/dev/null 2>/dev/null
  133.  
  134. # Find our minor version
  135. firehol_minor_version() {
  136. ${CAT_CMD} <<"EOF" | ${CUT_CMD} -d ' ' -f 3 | ${CUT_CMD} -d '.' -f 2
  137. $Id: firehol.sh,v 1.226 2005/01/25 21:28:19 ktsaou Exp $
  138. EOF
  139. }
  140.  
  141. FIREHOL_MINOR_VERSION=`firehol_minor_version`
  142. ${EXPR_CMD} ${FIREHOL_MINOR_VERSION} + 0 >/dev/null 2>&1
  143. if [ $? -ne 0 ]
  144. then
  145.     FIREHOL_MINOR_VERSION=220
  146. fi
  147.  
  148.  
  149. # Initialize iptables
  150. ${IPTABLES_CMD} -nxvL >/dev/null 2>&1
  151.  
  152.  
  153. # ------------------------------------------------------------------------------
  154. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  155. # ------------------------------------------------------------------------------
  156. #
  157. # GLOBAL DEFAULTS
  158. #
  159. # ------------------------------------------------------------------------------
  160. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  161. # ------------------------------------------------------------------------------
  162.  
  163. # ----------------------------------------------------------------------
  164. # Directories and files
  165.  
  166. # These files will be created and deleted during our run.
  167. FIREHOL_DIR="/tmp/.firehol-tmp-$$-${RANDOM}-${RANDOM}"
  168. FIREHOL_CHAINS_DIR="${FIREHOL_DIR}/chains"
  169. FIREHOL_OUTPUT="${FIREHOL_DIR}/firehol-out.sh"
  170. FIREHOL_SAVED="${FIREHOL_DIR}/firehol-save.sh"
  171. FIREHOL_TMP="${FIREHOL_DIR}/firehol-tmp.sh"
  172.  
  173. FIREHOL_SPOOL_DIR="/var/spool/firehol"
  174.  
  175. # The default configuration file
  176. # It can be changed on the command line
  177. FIREHOL_CONFIG_DIR="/etc/firehol"
  178. FIREHOL_CONFIG="${FIREHOL_CONFIG_DIR}/firehol.conf"
  179.  
  180. # Where /etc/init.d/iptables expects its configuration?
  181. # Leave it empty for automatic detection
  182. FIREHOL_AUTOSAVE=
  183.  
  184.  
  185. # ------------------------------------------------------------------------------
  186. # Make sure we automatically cleanup when we exit.
  187. # WHY:
  188. # Even a CTRL-C will call this and we will not leave temp files.
  189. # Also, if a configuration file breaks, we will detect this too.
  190.  
  191. firehol_exit() {
  192.     if [ -f "${FIREHOL_SAVED}" ]
  193.     then
  194.         echo
  195.         echo -n $"FireHOL: Restoring old firewall:"
  196.         iptables-restore <"${FIREHOL_SAVED}"
  197.         if [ $? -eq 0 ]
  198.         then
  199.             success $"FireHOL: Restoring old firewall:"
  200.         else
  201.             failure $"FireHOL: Restoring old firewall:"
  202.         fi
  203.         echo
  204.     fi
  205.     
  206.     test -d "${FIREHOL_DIR}" && ${RM_CMD} -rf "${FIREHOL_DIR}"
  207.     return 0
  208. }
  209.  
  210. # Run our exit even if we don't call exit.
  211. trap firehol_exit EXIT
  212.  
  213.  
  214. # ------------------------------------------------------------------------------
  215. # Create the directories we need.
  216.  
  217. if [ ! -d "${FIREHOL_CONFIG_DIR}" -a -f /etc/firehol.conf ]
  218. then
  219.     "${MKDIR_CMD}" "${FIREHOL_CONFIG_DIR}"            || exit 1
  220.     "${CHOWN_CMD}" root:root "${FIREHOL_CONFIG_DIR}"    || exit 1
  221.     "${CHMOD_CMD}" 700 "${FIREHOL_CONFIG_DIR}"        || exit 1
  222.     "${MV_CMD}" /etc/firehol.conf "${FIREHOL_CONFIG}"    || exit 1
  223.     
  224.     echo >&2
  225.     echo >&2
  226.     echo >&2 "NOTICE: Your config file /etc/firehol.conf has been moved to ${FIREHOL_CONFIG}"
  227.     echo >&2
  228.     sleep 5
  229. fi
  230.  
  231. # Externally defined services can be placed in "${FIREHOL_CONFIG_DIR}/services/"
  232. if [ ! -d "${FIREHOL_CONFIG_DIR}/services" ]
  233. then
  234.     "${MKDIR_CMD}" "${FIREHOL_CONFIG_DIR}/services"
  235.     if [ $? -ne 0 ]
  236.     then
  237.         echo >&2
  238.         echo >&2
  239.         echo >&2 "FireHOL needs to create the directory '${FIREHOL_CONFIG_DIR}/services', but it cannot."
  240.         echo >&2 "Possibly you have a file with this name, or something else is happening."
  241.         echo >&2 "Please solve this issue and retry".
  242.         echo >&2
  243.         exit 1
  244.     fi
  245.     "${CHOWN_CMD}" root:root "${FIREHOL_CONFIG_DIR}/services"
  246.     "${CHMOD_CMD}" 700 "${FIREHOL_CONFIG_DIR}/services"
  247. fi
  248.  
  249. # Remove any old directories that might be there.
  250. if [ -d "${FIREHOL_DIR}" ]
  251. then
  252.     "${RM_CMD}" -rf "${FIREHOL_DIR}"
  253.     if [ $? -ne 0 -o -e "${FIREHOL_DIR}" ]
  254.     then
  255.         echo >&2
  256.         echo >&2
  257.         echo >&2 "Cannot clean temporary directory '${FIREHOL_DIR}'."
  258.         echo >&2
  259.         exit 1
  260.     fi
  261. fi
  262. "${MKDIR_CMD}" "${FIREHOL_DIR}"                || exit 1
  263. "${MKDIR_CMD}" "${FIREHOL_CHAINS_DIR}"            || exit 1
  264.  
  265.  
  266. # Make sure we have a directory for our data.
  267. if [ ! -d "${FIREHOL_SPOOL_DIR}" ]
  268. then
  269.     "${MKDIR_CMD}" "${FIREHOL_SPOOL_DIR}"            || exit 1
  270.     "${CHOWN_CMD}" root:root "${FIREHOL_CONFIG_DIR}"    || exit 1
  271.     "${CHMOD_CMD}" 700 "${FIREHOL_CONFIG_DIR}"        || exit 1
  272. fi
  273.  
  274.  
  275. # ------------------------------------------------------------------------------
  276. # IP definitions
  277.  
  278. # IANA Reserved IPv4 address space
  279. # Suggested by Fco.Felix Belmonte <ffelix@gescosoft.com>
  280. # Optimized (CIDR) by Marc 'HE' Brockschmidt <marc@marcbrockschmidt.de>
  281. # Further optimized and reduced by http://www.vergenet.net/linux/aggregate/
  282. # The supplied get-iana.sh uses 'aggregate-flim' if it finds it in the path.
  283. RESERVED_IPS="0.0.0.0/7 2.0.0.0/8 5.0.0.0/8 7.0.0.0/8 23.0.0.0/8 27.0.0.0/8 31.0.0.0/8 36.0.0.0/7 39.0.0.0/8 41.0.0.0/8 42.0.0.0/8 73.0.0.0/8 74.0.0.0/7 76.0.0.0/6 89.0.0.0/8 90.0.0.0/7 92.0.0.0/6 96.0.0.0/3 173.0.0.0/8 174.0.0.0/7 176.0.0.0/5 184.0.0.0/6 189.0.0.0/8 190.0.0.0/8 197.0.0.0/8 223.0.0.0/8 240.0.0.0/4"
  284.  
  285. # Private IPv4 address space
  286. # Suggested by Fco.Felix Belmonte <ffelix@gescosoft.com>
  287. # Revised by me according to RFC 3330. Explanation:
  288. # 10.0.0.0/8       => RFC 1918: IANA Private Use
  289. # 169.254.0.0/16   => Link Local
  290. # 192.0.2.0/24     => Test Net
  291. # 192.88.99.0/24   => RFC 3068: 6to4 anycast & RFC 2544: Benchmarking addresses
  292. # 192.168.0.0/16   => RFC 1918: Private use
  293. PRIVATE_IPS="10.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.0.2.0/24 192.88.99.0/24 192.168.0.0/16"
  294.  
  295. # The multicast address space
  296. MULTICAST_IPS="224.0.0.0/4"
  297.  
  298. # A shortcut to have all the Internet unroutable addresses in one
  299. # variable
  300. UNROUTABLE_IPS="${RESERVED_IPS} ${PRIVATE_IPS}"
  301.  
  302. # ----------------------------------------------------------------------
  303.  
  304. # The default policy for the interface commands of the firewall.
  305. # This can be controlled on a per interface basis using the
  306. # policy interface subscommand. 
  307. DEFAULT_INTERFACE_POLICY="DROP"
  308.  
  309. # Which is the filter table chains policy during firewall activation?
  310. FIREHOL_INPUT_ACTIVATION_POLICY="ACCEPT"
  311. FIREHOL_OUTPUT_ACTIVATION_POLICY="ACCEPT"
  312. FIREHOL_FORWARD_ACTIVATION_POLICY="ACCEPT"
  313.  
  314. # Should we drop all INVALID packets always?
  315. FIREHOL_DROP_INVALID=0
  316.  
  317. # What to do with unmatched packets?
  318. # To change these, simply define them the configuration file.
  319. UNMATCHED_INPUT_POLICY="DROP"
  320. UNMATCHED_OUTPUT_POLICY="DROP"
  321. UNMATCHED_ROUTER_POLICY="DROP"
  322.  
  323. # Options for iptables LOG action.
  324. # These options will be added to all LOG actions FireHOL will generate.
  325. # To change them, type such a line in the configuration file.
  326. # FIREHOL_LOG_OPTIONS="--log-tcp-sequence --log-tcp-options --log-ip-options"
  327. FIREHOL_LOG_OPTIONS=""
  328. FIREHOL_LOG_LEVEL="warning"
  329. FIREHOL_LOG_MODE="LOG"
  330. FIREHOL_LOG_FREQUENCY="1/second"
  331. FIREHOL_LOG_BURST="5"
  332.  
  333. # The client ports to be used for "default" client ports when the
  334. # client specified is a foreign host.
  335. # We give all ports above 1000 because a few systems (like Solaris)
  336. # use this range.
  337. # Note that FireHOL will ask the kernel for default client ports of
  338. # the local host. This only applies to client ports of remote hosts.
  339. DEFAULT_CLIENT_PORTS="1024:65535"
  340.  
  341. # Get the default client ports from the kernel configuration.
  342. # This is formed to a range of ports to be used for all "default"
  343. # client ports when the client specified is the localhost.
  344. LOCAL_CLIENT_PORTS_LOW=`${SYSCTL_CMD} net.ipv4.ip_local_port_range | ${CUT_CMD} -d '=' -f 2 | ${CUT_CMD} -f 1`
  345. LOCAL_CLIENT_PORTS_HIGH=`${SYSCTL_CMD} net.ipv4.ip_local_port_range | ${CUT_CMD} -d '=' -f 2 | ${CUT_CMD} -f 2`
  346. LOCAL_CLIENT_PORTS="${LOCAL_CLIENT_PORTS_LOW}:${LOCAL_CLIENT_PORTS_HIGH}"
  347.  
  348.  
  349. # ----------------------------------------------------------------------
  350. # This is our version number. It is increased when the configuration
  351. # file commands and arguments change their meaning and usage, so that
  352. # the user will have to review it more precisely.
  353. FIREHOL_VERSION=5
  354.  
  355.  
  356. # ----------------------------------------------------------------------
  357. # The initial line number of the configuration file.
  358. FIREHOL_LINEID="INIT"
  359.  
  360. # Variable kernel module requirements.
  361. # Suggested by Fco.Felix Belmonte <ffelix@gescosoft.com>
  362. # Note that each of the complex services
  363. # may add to this variable the kernel modules it requires.
  364. # See rules_ftp() bellow for an example.
  365. FIREHOL_KERNEL_MODULES=""
  366. #
  367. # In the configuration file you can write:
  368. #
  369. #                     require_kernel_module <module_name>
  370. # to have FireHOL require a specific module for the configurarion.
  371.  
  372. # Set this to 1 in the configuration file to have FireHOL complex
  373. # services' rules load NAT kernel modules too.
  374. FIREHOL_NAT=0
  375.  
  376. # Set this to 1 in the configuration file if routing should be enabled
  377. # in the kernel.
  378. FIREHOL_ROUTING=0
  379.  
  380. # Services may add themeselves to this variable so that the service "all" will
  381. # also call them.
  382. # By default it is empty - only rules programmers should change this.
  383. ALL_SHOULD_ALSO_RUN=
  384.  
  385.  
  386. # ------------------------------------------------------------------------------
  387. # Various Defaults
  388.  
  389. # If set to 1, we are just going to present the resulting firewall instead of
  390. # installing it.
  391. # It can be changed on the command line
  392. FIREHOL_DEBUG=0
  393.  
  394. # If set to 1, the firewall will be saved for normal iptables processing.
  395. # It can be changed on the command line
  396. FIREHOL_SAVE=0
  397.  
  398. # If set to 1, the firewall will be restored if you don't commit it.
  399. # It can be changed on the command line
  400. FIREHOL_TRY=1
  401.  
  402. # If set to 1, FireHOL enters interactive mode to answer questions.
  403. # It can be changed on the command line
  404. FIREHOL_EXPLAIN=0
  405.  
  406. # If set to 1, FireHOL enters a wizard mode to help the user build a firewall.
  407. # It can be changed on the command line
  408. FIREHOL_WIZARD=0
  409.  
  410. # If set to 0, FireHOL will not try to load the required kernel modules.
  411. # It can be set in the configuration file.
  412. FIREHOL_LOAD_KERNEL_MODULES=1
  413.  
  414. # If set to 1, FireHOL will output the commands of the configuration file
  415. # with variables expanded.
  416. FIREHOL_CONF_SHOW=1
  417.  
  418.  
  419. # ------------------------------------------------------------------------------
  420. # Keep information about the current primary command
  421. # Primary commands are: interface, router
  422.  
  423. work_counter=0
  424. work_cmd=
  425. work_realcmd=("(unset)")
  426. work_name=
  427. work_inface=
  428. work_outface=
  429. work_policy="${DEFAULT_INTERFACE_POLICY}"
  430. work_error=0
  431. work_function="Initializing"
  432.  
  433.  
  434. # ------------------------------------------------------------------------------
  435. # Keep status information
  436.  
  437. # 0 = no errors, 1 = there were errors in the script
  438. work_final_status=0
  439.  
  440. # This variable is used for generating dynamic chains when needed for
  441. # combined negative statements (AND) implied by the "not" parameter
  442. # to many FireHOL directives.
  443. # What FireHOL is doing to accomplish this, is to produce dynamically
  444. # a linked list of iptables chains with just one condition each, making
  445. # the packets to traverse from chain to chain when matched, to reach
  446. # their final destination.
  447. FIREHOL_DYNAMIC_CHAIN_COUNTER=1
  448.  
  449. # If set to 0, FireHOL will not trust interface lo for all traffic.
  450. # This means the admin could setup a firewall on lo.
  451. FIREHOL_TRUST_LOOPBACK=1
  452.  
  453. # Services API version
  454. FIREHOL_SERVICES_API="1"
  455.  
  456.  
  457. # ------------------------------------------------------------------------------
  458. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  459. # ------------------------------------------------------------------------------
  460. #
  461. # SIMPLE SERVICES DEFINITIONS
  462. #
  463. # ------------------------------------------------------------------------------
  464. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  465. # ------------------------------------------------------------------------------
  466. # The following are definitions for simple services.
  467. # We define as "simple" the services that are implemented using a single socket,
  468. # initiated by the client and used by the server.
  469. #
  470. # The following list is sorted by service name.
  471.  
  472. server_AH_ports="51/any"
  473. client_AH_ports="any"
  474.  
  475. # Debian package proxy
  476. server_aptproxy_ports="tcp/9999"
  477. client_aptproxy_ports="default"
  478.  
  479. # APC UPS Server (these ports have to be accessible on all machines NOT
  480. # directly connected to the UPS (e.g. the slaves)
  481. server_apcupsd_ports="tcp/6544"
  482. client_apcupsd_ports="default"
  483.  
  484. server_apcupsdnis_ports="tcp/3551"
  485. client_apcupsdnis_ports="default"
  486.  
  487. server_asterisk_ports="tcp/5038"
  488. client_asterisk_ports="default"
  489.  
  490. server_cups_ports="tcp/631 udp/631"
  491. client_cups_ports="default 631"
  492.  
  493. server_cvspserver_ports="tcp/2401"
  494. client_cvspserver_ports="default"
  495.  
  496. server_darkstat_ports="tcp/666"
  497. client_darkstat_ports="default"
  498.  
  499. server_daytime_ports="tcp/13"
  500. client_daytime_ports="default"
  501.  
  502. server_dcc_ports="udp/6277"
  503. client_dcc_ports="default"
  504.  
  505. server_dcpp_ports="tcp/1412 udp/1412"
  506. client_dcpp_ports="default"
  507.  
  508. server_dns_ports="udp/53 tcp/53"
  509. client_dns_ports="any"
  510.  
  511. # DHCP Relaying (server is the relay server which behaves like a client
  512. # towards the real DHCP Server); I'm not sure about this one...
  513. server_dhcprelay_ports="udp/67"
  514. client_dhcprelay_ports="67"
  515.  
  516. server_dict_ports="tcp/2628"
  517. client_dict_ports="default"
  518.  
  519. # DISTCC is the distributed gcc for Gentoo
  520. server_distcc_ports="tcp/3632"
  521. client_distcc_ports="default"
  522.  
  523. server_eserver_ports="tcp/4661 udp/4661 udp/4665"
  524. client_eserver_ports="any"
  525.  
  526. server_ESP_ports="50/any"
  527. client_ESP_ports="any"
  528.  
  529. server_echo_ports="tcp/7"
  530. client_echo_ports="default"
  531.  
  532. server_finger_ports="tcp/79"
  533. client_finger_ports="default"
  534.  
  535. # giFT modules' ports
  536. # Gnutella  = tcp/4302
  537. # FastTrack = tcp/1214
  538. # OpenFT    = tcp/2182 tcp/2472
  539. server_gift_ports="tcp/4302 tcp/1214 tcp/2182 tcp/2472"
  540. client_gift_ports="any"
  541.  
  542. # giFT User Interface connections
  543. server_giftui_ports="tcp/1213"
  544. client_giftui_ports="default"
  545.  
  546. # gkrellmd (from gkrellm.net)
  547. server_gkrellmd_ports="tcp/19150"
  548. client_gkrellmd_ports="default"
  549.  
  550. server_GRE_ports="47/any"
  551. client_GRE_ports="any"
  552.  
  553. server_h323_ports="tcp/1720 tcp/1731"
  554. client_h323_ports="default"
  555.  
  556. # We assume heartbeat uses ports in the range 690 to 699
  557. server_heartbeat_ports="udp/690:699"
  558. client_heartbeat_ports="default"
  559.  
  560. server_http_ports="tcp/80"
  561. client_http_ports="default"
  562.  
  563. server_https_ports="tcp/443"
  564. client_https_ports="default"
  565.  
  566. server_iax_ports="udp/5036"
  567. client_iax_ports="default"
  568.  
  569. server_iax2_ports="udp/5469 udp/4569"
  570. client_iax2_ports="default"
  571.  
  572. server_ICMP_ports="icmp/any"
  573. client_ICMP_ports="any"
  574.  
  575. server_icmp_ports="icmp/any"
  576. client_icmp_ports="any"
  577. # ALL_SHOULD_ALSO_RUN="${ALL_SHOULD_ALSO_RUN} icmp"
  578.  
  579. # Squid' ICP port
  580. server_icp_ports="udp/3130"
  581. client_icp_ports="3130"
  582.  
  583. server_ident_ports="tcp/113"
  584. client_ident_ports="default"
  585.  
  586. server_imap_ports="tcp/143"
  587. client_imap_ports="default"
  588.  
  589. server_imaps_ports="tcp/993"
  590. client_imaps_ports="default"
  591.  
  592. server_irc_ports="tcp/6667"
  593. client_irc_ports="default"
  594. require_irc_modules="ip_conntrack_irc"
  595. require_irc_nat_modules="ip_nat_irc"
  596. ALL_SHOULD_ALSO_RUN="${ALL_SHOULD_ALSO_RUN} irc"
  597.  
  598. # for IPSec Key negotiation
  599. server_isakmp_ports="udp/500"
  600. client_isakmp_ports="500"
  601.  
  602. server_jabber_ports="tcp/5222 tcp/5223"
  603. client_jabber_ports="default"
  604.  
  605. server_jabberd_ports="tcp/5222 tcp/5223 tcp/5269"
  606. client_jabberd_ports="default"
  607.  
  608. server_ldap_ports="tcp/389"
  609. client_ldap_ports="default"
  610.  
  611. server_ldaps_ports="tcp/636"
  612. client_ldaps_ports="default"
  613.  
  614. server_lpd_ports="tcp/515"
  615. client_lpd_ports="721:731 default"
  616.  
  617. server_microsoft_ds_ports="tcp/445"
  618. client_microsoft_ds_ports="default"
  619.  
  620. server_mms_ports="tcp/1755 udp/1755"
  621. client_mms_ports="default"
  622. require_mms_modules="ip_conntrack_mms"
  623. require_mms_nat_modules="ip_nat_mms"
  624. # this will produce warnings on most distribution
  625. # because the mms module is not there:
  626. # ALL_SHOULD_ALSO_RUN="${ALL_SHOULD_ALSO_RUN} mms"
  627.  
  628. server_msn_ports="tcp/6891"
  629. client_msn_ports="default"
  630.  
  631. server_mysql_ports="tcp/3306"
  632. client_mysql_ports="default"
  633.  
  634. # Veritas NetBackup
  635. server_netbackup_ports="tcp/13701 tcp/13711 tcp/13720 tcp/13721 tcp/13724 tcp/13782 tcp/13783"
  636. client_netbackup_ports="any"
  637.  
  638. server_netbios_ns_ports="udp/137"
  639. client_netbios_ns_ports="default 137"
  640.  
  641. server_netbios_dgm_ports="udp/138"
  642. client_netbios_dgm_ports="default 138"
  643.  
  644. server_netbios_ssn_ports="tcp/139"
  645. client_netbios_ssn_ports="default"
  646.  
  647. server_nntp_ports="tcp/119"
  648. client_nntp_ports="default"
  649.  
  650. server_nntps_ports="tcp/563"
  651. client_nntps_ports="default"
  652.  
  653. server_ntp_ports="udp/123 tcp/123"
  654. client_ntp_ports="123 default"
  655.  
  656. # Network UPS Tools
  657. server_nut_ports="tcp/3493 udp/3493"
  658. client_nut_ports="default"
  659.  
  660. # NoMachine's NX server
  661. server_nxserver_ports="tcp/5000:5200"
  662. client_nxserver_ports="default"
  663.  
  664. # Oracle database
  665. server_oracle_ports="tcp/1521"
  666. client_oracle_ports="default"
  667.  
  668. server_pop3_ports="tcp/110"
  669. client_pop3_ports="default"
  670.  
  671. server_pop3s_ports="tcp/995"
  672. client_pop3s_ports="default"
  673.  
  674. # Portmap clients appear to use ports bellow 1024
  675. server_portmap_ports="udp/111 tcp/111"
  676. client_portmap_ports="500:65535"
  677.  
  678. server_postgres_ports="tcp/5432"
  679. client_postgres_ports="default"
  680.  
  681. # Privacy Proxy
  682. server_privoxy_ports="tcp/8118"
  683. client_privoxy_ports="default"
  684.  
  685. server_radius_ports="udp/1812 udp/1813"
  686. client_radius_ports="default"
  687.  
  688. server_radiusproxy_ports="udp/1814"
  689. client_radiusproxy_ports="default"
  690.  
  691. server_radiusold_ports="udp/1645 udp/1646"
  692. client_radiusold_ports="default"
  693.  
  694. server_radiusoldproxy_ports="udp/1647"
  695. client_radiusoldproxy_ports="default"
  696.  
  697. server_rdp_ports="tcp/3389"
  698. client_rdp_ports="default"
  699.  
  700. server_rndc_ports="tcp/953"
  701. client_rndc_ports="default"
  702.  
  703. server_rsync_ports="tcp/873 udp/873"
  704. client_rsync_ports="default"
  705.  
  706. server_rtp_ports="udp/10000:20000"
  707. client_rtp_ports="any"
  708.  
  709. server_sip_ports="udp/5060"
  710. client_sip_ports="default"
  711.  
  712. server_socks_ports="tcp/1080 udp/1080"
  713. client_socks_ports="default"
  714.  
  715. server_squid_ports="tcp/3128"
  716. client_squid_ports="default"
  717.  
  718. server_smtp_ports="tcp/25"
  719. client_smtp_ports="default"
  720.  
  721. server_smtps_ports="tcp/465"
  722. client_smtps_ports="default"
  723.  
  724. server_snmp_ports="udp/161"
  725. client_snmp_ports="default"
  726.  
  727. server_snmptrap_ports="udp/162"
  728. client_snmptrap_ports="any"
  729.  
  730. server_ssh_ports="tcp/22"
  731. client_ssh_ports="default"
  732.  
  733. server_stun_ports="udp/3478 udp/3479"
  734. client_stun_ports="any"
  735.  
  736. # SMTP over SSL/TLS submission
  737. server_submission_ports="tcp/587"
  738. client_submission_ports="default"
  739.  
  740. # Sun RCP is an alias for service portmap
  741. server_sunrpc_ports="${server_portmap_ports}"
  742. client_sunrpc_ports="${client_portmap_ports}"
  743.  
  744. server_swat_ports="tcp/901"
  745. client_swat_ports="default"
  746.  
  747. server_syslog_ports="udp/514"
  748. client_syslog_ports="syslog default"
  749.  
  750. server_telnet_ports="tcp/23"
  751. client_telnet_ports="default"
  752.  
  753. server_time_ports="tcp/37 udp/37"
  754. client_time_ports="default"
  755.  
  756. server_upnp_ports="udp/1900 tcp/2869"
  757. client_upnp_ports="default"
  758.  
  759. server_uucp_ports="tcp/540"
  760. client_uucp_ports="default"
  761.  
  762. server_whois_ports="tcp/43"
  763. client_whois_ports="default"
  764.  
  765. server_vmware_ports="tcp/902"
  766. client_vmware_ports="default"
  767.  
  768. server_vmwareauth_ports="tcp/903"
  769. client_vmwareauth_ports="default"
  770.  
  771. server_vmwareweb_ports="tcp/8222"
  772. client_vmwareweb_ports="default"
  773.  
  774. server_vnc_ports="tcp/5900:5903"
  775. client_vnc_ports="default"
  776.  
  777. server_webcache_ports="tcp/8080"
  778. client_webcache_ports="default"
  779.  
  780. server_webmin_ports="tcp/10000"
  781. client_webmin_ports="default"
  782.  
  783. server_xdmcp_ports="udp/177"
  784. client_xdmcp_ports="default"
  785.  
  786.  
  787. # ------------------------------------------------------------------------------
  788. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  789. # ------------------------------------------------------------------------------
  790. #
  791. # COMPLEX SERVICES DEFINITIONS
  792. #
  793. # ------------------------------------------------------------------------------
  794. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  795. # ------------------------------------------------------------------------------
  796. # The following are definitions for complex services.
  797. # We define as "complex" the services that are implemented using multiple sockets.
  798.  
  799. # Each function bellow is organized in three parts:
  800. # 1) A Header, common to each and every function
  801. # 2) The rules required for the INPUT of the server
  802. # 3) The rules required for the OUTPUT of the server
  803. #
  804. # The Header part, together with the "reverse" keyword can reverse the rules so
  805. # that if we are implementing a client the INPUT will become OUTPUT and vice versa.
  806. #
  807. # In most the cases the input and output rules are the same with the following
  808. # differences:
  809. #
  810. # a) The output rules begin with the "reverse" keyword, which reverses:
  811. #    inface/outface, src/dst, sport/dport
  812. # b) The output rules use ${out}_${mychain} instead of ${in}_${mychain}
  813. # c) The state rules match the client operation, not the server.
  814.  
  815.  
  816. # --- DHCP --------------------------------------------------------------------
  817.  
  818. rules_dhcp() {
  819.         local mychain="${1}"; shift
  820.     local type="${1}"; shift
  821.     
  822.     local in=in
  823.     local out=out
  824.     if [ "${type}" = "client" ]
  825.     then
  826.         in=out
  827.         out=in
  828.     fi
  829.     
  830.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  831.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  832.     then
  833.         client_ports="${LOCAL_CLIENT_PORTS}"
  834.     fi
  835.     
  836.     # ----------------------------------------------------------------------
  837.     
  838.     set_work_function "Setting up rules for DHCP (${type})"
  839.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport "68" dport "67" || return 1
  840.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport "68" dport "67" || return 1
  841.     
  842.     return 0
  843. }
  844.  
  845.  
  846. # --- EMULE --------------------------------------------------------------------
  847.  
  848. rules_emule() {
  849.         local mychain="${1}"; shift
  850.     local type="${1}"; shift
  851.     
  852.     local in=in
  853.     local out=out
  854.     if [ "${type}" = "client" ]
  855.     then
  856.         in=out
  857.         out=in
  858.     fi
  859.     
  860.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  861.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  862.     then
  863.         client_ports="${LOCAL_CLIENT_PORTS}"
  864.     fi
  865.     
  866.     # ----------------------------------------------------------------------
  867.     
  868.     # allow incomming to server tcp/4662
  869.     set_work_function "Setting up rules for EMULE/client-to-server tcp/4662 (${type})"
  870.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" sport any dport 4662 state NEW,ESTABLISHED || return 1
  871.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" sport any dport 4662 state ESTABLISHED     || return 1
  872.     
  873.     # allow outgoing to client tcp/4662
  874.     set_work_function "Setting up rules for EMULE/server-to-client tcp/4662 (${type})"
  875.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" dport any sport 4662 state NEW,ESTABLISHED || return 1
  876.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" dport any sport 4662 state ESTABLISHED     || return 1
  877.     
  878.     # allow incomming to server udp/4672
  879.     set_work_function "Setting up rules for EMULE/client-to-server udp/4672 (${type})"
  880.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport any dport 4672 state NEW,ESTABLISHED || return 1
  881.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport any dport 4672 state ESTABLISHED     || return 1
  882.     
  883.     # allow outgoing to client udp/4672
  884.     set_work_function "Setting up rules for EMULE/server-to-client udp/4672 (${type})"
  885.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" dport any sport 4672 state NEW,ESTABLISHED || return 1
  886.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" dport any sport 4672 state ESTABLISHED     || return 1
  887.     
  888.     # allow incomming to server tcp/4661
  889.     set_work_function "Setting up rules for EMULE/client-to-server tcp/4661 (${type})"
  890.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" sport any dport 4661 state NEW,ESTABLISHED || return 1
  891.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" sport any dport 4661 state ESTABLISHED     || return 1
  892.     
  893.     # allow incomming to server udp/4665
  894.     set_work_function "Setting up rules for EMULE/client-to-server udp/4665 (${type})"
  895.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport any dport 4665 state NEW,ESTABLISHED || return 1
  896.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport any dport 4665 state ESTABLISHED     || return 1
  897.     
  898.     return 0
  899. }
  900.  
  901.  
  902. # --- HYLAFAX ------------------------------------------------------------------
  903. # Written by: Franscisco Javier Felix <ffelix@gescosoft.com>
  904.  
  905. rules_hylafax() {
  906.         local mychain="${1}"; shift
  907.     local type="${1}"; shift
  908.     
  909.     local in=in
  910.     local out=out
  911.     if [ "${type}" = "client" ]
  912.     then
  913.         in=out
  914.         out=in
  915.     fi
  916.     
  917.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  918.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  919.     then
  920.         client_ports="${LOCAL_CLIENT_PORTS}"
  921.     fi
  922.     
  923.     # ----------------------------------------------------------------------
  924.     
  925.     # allow incomming to server tcp/4559
  926.     set_work_function "Setting up rules for HYLAFAX/client-to-server tcp/4559 (${type})"
  927.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" sport any dport 4559 state NEW,ESTABLISHED || return 1
  928.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" sport any dport 4559 state ESTABLISHED     || return 1
  929.     
  930.     # allow outgoing to client from server tcp/4558
  931.     set_work_function "Setting up rules for HYLAFAX/server-to-client from server tcp/4558 (${type})"
  932.     rule ${out}        action "$@" chain "${out}_${mychain}" proto "tcp" sport 4558 dport any state NEW,ESTABLISHED || return 1
  933.         rule ${in} reverse action "$@" chain "${in}_${mychain}"  proto "tcp" sport 4558 dport any state ESTABLISHED     || return 1
  934.     
  935.     return 0
  936. }
  937.  
  938.  
  939. # --- SAMBA --------------------------------------------------------------------
  940.  
  941. rules_samba() {
  942.         local mychain="${1}"; shift
  943.     local type="${1}"; shift
  944.     
  945.     local in=in
  946.     local out=out
  947.     if [ "${type}" = "client" ]
  948.     then
  949.         in=out
  950.         out=in
  951.     fi
  952.     
  953.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  954.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  955.     then
  956.         client_ports="${LOCAL_CLIENT_PORTS}"
  957.     fi
  958.     
  959.     # ----------------------------------------------------------------------
  960.     
  961.     set_work_function "Setting up rules for SAMBA/NETBIOS-NS (${type})"
  962.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport "137 ${client_ports}"  dport 137 state NEW,ESTABLISHED || return 1
  963.     
  964.     # NETBIOS initiates based on the broadcast address of an interface
  965.     # (request goes to broadcast address) but the server responds from
  966.     # its own IP address. This makes the server samba accept statement
  967.     # drop the server reply.
  968.     # Bellow is a hack, that allows a linux samba server to respond
  969.     # correctly, as it allows new outgoing connections from the well
  970.     # known netbios-ns port to the clients high ports.
  971.     # For clients and routers this hack is not applied because it
  972.     # would be a huge security hole.
  973.     if [ "${type}" = "server" -a "${work_cmd}" = "interface" ]
  974.     then
  975.         rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport "137 ${client_ports}"  dport 137 state NEW,ESTABLISHED || return 1
  976.     else
  977.         rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport "137 ${client_ports}"  dport 137 state ESTABLISHED     || return 1
  978.     fi
  979.     
  980.     set_work_function "Setting up rules for SAMBA/NETBIOS-DGM (${type})"
  981.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport "138 ${client_ports}" dport 138 state NEW,ESTABLISHED || return 1
  982.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport "138 ${client_ports}" dport 138 state ESTABLISHED     || return 1
  983.     
  984.     set_work_function "Setting up rules for SAMBA/NETBIOS-SSN (${type})"
  985.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" sport "${client_ports}" dport 139 state NEW,ESTABLISHED || return 1
  986.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" sport "${client_ports}" dport 139 state ESTABLISHED     || return 1
  987.     
  988.     set_work_function "Setting up rules for SAMBA/MICROSOFT_DS (${type})"
  989.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" sport "${client_ports}" dport 445 state NEW,ESTABLISHED || return 1
  990.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" sport "${client_ports}" dport 445 state ESTABLISHED     || return 1
  991.     
  992.     return 0
  993. }
  994.  
  995.  
  996. # --- PPTP --------------------------------------------------------------------
  997.  
  998. rules_pptp() {
  999.         local mychain="${1}"; shift
  1000.     local type="${1}"; shift
  1001.     
  1002.     local in=in
  1003.     local out=out
  1004.     if [ "${type}" = "client" ]
  1005.     then
  1006.         in=out
  1007.         out=in
  1008.     fi
  1009.     
  1010.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1011.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1012.     then
  1013.         client_ports="${LOCAL_CLIENT_PORTS}"
  1014.     fi
  1015.     
  1016.     # ----------------------------------------------------------------------
  1017.     
  1018.     set_work_function "Setting up rules for PPTP/initial connection (${type})"
  1019.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp" sport "${client_ports}" dport "1723" state NEW,ESTABLISHED || return 1
  1020.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp" sport "${client_ports}" dport "1723" state ESTABLISHED     || return 1
  1021.     
  1022.     set_work_function "Setting up rules for PPTP/tunnel GRE traffic (${type})"
  1023.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "47"    || return 1
  1024.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "47"    || return 1
  1025.     
  1026.     return 0
  1027. }
  1028.  
  1029.  
  1030. # --- NFS ----------------------------------------------------------------------
  1031.  
  1032. rules_nfs() {
  1033.         local mychain="${1}"; shift
  1034.     local type="${1}"; shift
  1035.     
  1036.     local in=in
  1037.     local out=out
  1038.     if [ "${type}" = "client" ]
  1039.     then
  1040.         in=out
  1041.         out=in
  1042.     fi
  1043.     
  1044.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1045.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1046.     then
  1047.         client_ports="${LOCAL_CLIENT_PORTS}"
  1048.     fi
  1049.     
  1050.     # ----------------------------------------------------------------------
  1051.     
  1052.     # This command requires in the client or route subcommands,
  1053.     # the first argument after the policy/action is a dst.
  1054.     
  1055.     local action="${1}"; shift
  1056.     local servers="localhost"
  1057.     
  1058.     if [ "${type}" = "client" -o ! "${work_cmd}" = "interface" ]
  1059.     then
  1060.         case "${1}" in
  1061.             dst|DST|destination|DESTINATION)
  1062.                 shift
  1063.                 local servers="${1}"
  1064.                 shift
  1065.                 ;;
  1066.                 
  1067.             *)
  1068.                 error "Please re-phrase to: ${type} nfs ${action} dst <NFS_SERVER> [other rules]"
  1069.                 return 1
  1070.                 ;;
  1071.         esac
  1072.     fi
  1073.     
  1074.     local x=
  1075.     for x in ${servers}
  1076.     do
  1077.         local tmp="${FIREHOL_DIR}/firehol.rpcinfo.$$.${RANDOM}"
  1078.         
  1079.         set_work_function "Getting RPC information from server '${x}'"
  1080.         
  1081.         rpcinfo -p ${x} >"${tmp}"
  1082.         if [ $? -gt 0 -o ! -s "${tmp}" ]
  1083.         then
  1084.             error "Cannot get rpcinfo from host '${x}' (using the previous firewall rules)"
  1085.             ${RM_CMD} -f "${tmp}"
  1086.             return 1
  1087.         fi
  1088.         
  1089.         local server_rquotad_ports="`${CAT_CMD} "${tmp}" | ${GREP_CMD} " rquotad$"  | ( while read a b proto port s; do echo "$proto/$port"; done ) | ${SORT_CMD} | ${UNIQ_CMD}`"
  1090.         local server_mountd_ports="`${CAT_CMD} "${tmp}" | ${GREP_CMD} " mountd$"  | ( while read a b proto port s; do echo "$proto/$port"; done ) | ${SORT_CMD} | ${UNIQ_CMD}`"
  1091.         local server_lockd_ports="`${CAT_CMD} "${tmp}" | ${GREP_CMD} " nlockmgr$" | ( while read a b proto port s; do echo "$proto/$port"; done ) | ${SORT_CMD} | ${UNIQ_CMD}`"
  1092.         local server_nfsd_ports="`${CAT_CMD} "${tmp}" | ${GREP_CMD} " nfs$"       | ( while read a b proto port s; do echo "$proto/$port"; done ) | ${SORT_CMD} | ${UNIQ_CMD}`"
  1093.         
  1094.         test -z "${server_mountd_ports}" && error "Cannot find mountd ports for nfs server '${x}'" && return 1
  1095.         test -z "${server_lockd_ports}"  && error "Cannot find lockd ports for nfs server '${x}'" && return 1
  1096.         test -z "${server_nfsd_ports}"   && error "Cannot find nfsd ports for nfs server '${x}'" && return 1
  1097.         
  1098.         local dst=
  1099.         if [ ! "${x}" = "localhost" ]
  1100.         then
  1101.             dst="dst ${x}"
  1102.         fi
  1103.         
  1104.         if [ ! -z "${server_rquotad_ports}" ]
  1105.         then
  1106.             set_work_function "Processing rquotad rules for server '${x}'"
  1107.             rules_custom "${mychain}" "${type}" nfs-rquotad "${server_rquotad_ports}" "500:65535" "${action}" $dst "$@"
  1108.         fi
  1109.         
  1110.         set_work_function "Processing mountd rules for server '${x}'"
  1111.         rules_custom "${mychain}" "${type}" nfs-mountd "${server_mountd_ports}" "500:65535" "${action}" $dst "$@"
  1112.         
  1113.         set_work_function "Processing lockd rules for server '${x}'"
  1114.         rules_custom "${mychain}" "${type}" nfs-lockd "${server_lockd_ports}" "500:65535" "${action}" $dst "$@"
  1115.         
  1116.         set_work_function "Processing nfsd rules for server '${x}'"
  1117.         rules_custom "${mychain}" "${type}" nfs-nfsd   "${server_nfsd_ports}"   "500:65535" "${action}" $dst "$@"
  1118.         
  1119.         ${RM_CMD} -f "${tmp}"
  1120.         
  1121.         echo >&2 ""
  1122.         echo >&2 "WARNING:"
  1123.         echo >&2 "This firewall must be restarted if NFS server ${x} is restarted!"
  1124.         echo >&2 ""
  1125.     done
  1126.     
  1127.     return 0
  1128. }
  1129.  
  1130.  
  1131. # --- NIS ----------------------------------------------------------------------
  1132. # These rules work for client access only!
  1133. #
  1134. # Pushing changes to slave servers won't work if these rules are active
  1135. # somewhere between the master and its slaves, because it is impossible to
  1136. # predict the ports where "yppush" will be listening on each push.
  1137. #
  1138. # Pulling changes directly on the slaves will work, and could be improved
  1139. # performance-wise if these rules are modified to open "fypxfrd". This wasn't
  1140. # done because it doesn't make that much sense since pushing changes on the
  1141. # master server is the most common, and recommended, way to replicate maps.
  1142. #
  1143. # Created by Carlos Rodrigues <crlf@users.sourceforge.net>
  1144. # Feature Requests item #1050951 <https://sourceforge.net/tracker/?func=detail&atid=487695&aid=1050951&group_id=58425>
  1145.  
  1146. rules_nis() {
  1147.         local mychain="${1}"; shift
  1148.     local type="${1}"; shift
  1149.     
  1150.     local in=in
  1151.     local out=out
  1152.     if [ "${type}" = "client" ]
  1153.     then
  1154.         in=out
  1155.         out=in
  1156.     fi
  1157.     
  1158.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1159.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1160.     then
  1161.         client_ports="${LOCAL_CLIENT_PORTS}"
  1162.     fi
  1163.     
  1164.     # ----------------------------------------------------------------------
  1165.     
  1166.     # This command requires in the client or route subcommands,
  1167.     # the first argument after the policy/action is a dst.
  1168.     
  1169.     local action="${1}"; shift
  1170.     local servers="localhost"
  1171.     
  1172.     if [ "${type}" = "client" -o ! "${work_cmd}" = "interface" ]
  1173.     then
  1174.         case "${1}" in
  1175.             dst|DST|destination|DESTINATION)
  1176.                 shift
  1177.                 local servers="${1}"
  1178.                 shift
  1179.                 ;;
  1180.                 
  1181.             *)
  1182.                 error "Please re-phrase to: ${type} nis ${action} dst <NIS_SERVER> [other rules]"
  1183.                 return 1
  1184.                 ;;
  1185.         esac
  1186.     fi
  1187.     
  1188.     local x=
  1189.     for x in ${servers}
  1190.     do
  1191.         local tmp="${FIREHOL_DIR}/firehol.rpcinfo.$$.${RANDOM}"
  1192.         
  1193.         set_work_function "Getting RPC information from server '${x}'"
  1194.         
  1195.         rpcinfo -p ${x} >"${tmp}"
  1196.         if [ $? -gt 0 -o ! -s "${tmp}" ]
  1197.         then
  1198.             error "Cannot get rpcinfo from host '${x}' (using the previous firewall rules)"
  1199.             ${RM_CMD} -f "${tmp}"
  1200.             return 1
  1201.         fi
  1202.         
  1203.         local server_ypserv_ports="`${CAT_CMD} "${tmp}" | ${GREP_CMD} " ypserv$"  | ( while read a b proto port s; do echo "$proto/$port"; done ) | ${SORT_CMD} | ${UNIQ_CMD}`"
  1204.         local server_yppasswdd_ports="`${CAT_CMD} "${tmp}" | ${GREP_CMD} " yppasswdd$"  | ( while read a b proto port s; do echo "$proto/$port"; done ) | ${SORT_CMD} | ${UNIQ_CMD}`"
  1205.         
  1206.         test -z "${server_ypserv_ports}" && error "Cannot find ypserv ports for nis server '${x}'" && return 1
  1207.         
  1208.         local dst=
  1209.         if [ ! "${x}" = "localhost" ]
  1210.         then
  1211.             dst="dst ${x}"
  1212.         fi
  1213.         
  1214.         if [ ! -z "${server_yppasswd_ports}" ]
  1215.         then
  1216.             set_work_function "Processing yppasswd rules for server '${x}'"
  1217.             rules_custom "${mychain}" "${type}" nis-yppasswd "${server_yppasswdd_ports}" "500:65535" "${action}" $dst "$@"
  1218.         fi
  1219.         
  1220.         set_work_function "Processing ypserv rules for server '${x}'"
  1221.         rules_custom "${mychain}" "${type}" nis-ypserv "${server_ypserv_ports}" "500:65535" "${action}" $dst "$@"
  1222.         
  1223.         ${RM_CMD} -f "${tmp}"
  1224.         
  1225.         echo >&2 ""
  1226.         echo >&2 "WARNING:"
  1227.         echo >&2 "This firewall must be restarted if NIS server ${x} is restarted!"
  1228.         echo >&2 ""
  1229.     done
  1230.     
  1231.     return 0
  1232. }
  1233.  
  1234.  
  1235. # --- AMANDA -------------------------------------------------------------------
  1236. FIREHOL_AMANDA_PORTS="850:859"
  1237.  
  1238. rules_amanda() {
  1239.         local mychain="${1}"; shift
  1240.     local type="${1}"; shift
  1241.     
  1242.     local in=in
  1243.     local out=out
  1244.     if [ "${type}" = "client" ]
  1245.     then
  1246.         in=out
  1247.         out=in
  1248.     fi
  1249.     
  1250.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1251.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1252.     then
  1253.         client_ports="${LOCAL_CLIENT_PORTS}"
  1254.     fi
  1255.     
  1256.     # ----------------------------------------------------------------------
  1257.     
  1258.     set_work_function "*** AMANDA: See http://amanda.sourceforge.net/fom-serve/cache/139.html"
  1259.     
  1260.     
  1261.     set_work_function "Setting up rules for initial amanda server-to-client connection"
  1262.     rule ${out}        action "$@" chain "${out}_${mychain}" proto "udp" dport 10080 state NEW,ESTABLISHED || return 1
  1263.     rule ${in} reverse action "$@" chain "${in}_${mychain}"  proto "udp" dport 10080 state ESTABLISHED     || return 1
  1264.     
  1265.     
  1266.     set_work_function "Setting up rules for amanda data exchange client-to-server"
  1267.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "tcp udp" dport "${FIREHOL_AMANDA_PORTS}" state NEW,ESTABLISHED || return 1
  1268.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "tcp udp" dport "${FIREHOL_AMANDA_PORTS}" state ESTABLISHED     || return 1
  1269.     
  1270.     return 0
  1271. }
  1272.  
  1273. # --- FTP ----------------------------------------------------------------------
  1274.  
  1275. ALL_SHOULD_ALSO_RUN="${ALL_SHOULD_ALSO_RUN} ftp"
  1276.  
  1277. rules_ftp() {
  1278.         local mychain="${1}"; shift
  1279.     local type="${1}"; shift
  1280.     
  1281.     local in=in
  1282.     local out=out
  1283.     if [ "${type}" = "client" ]
  1284.     then
  1285.         in=out
  1286.         out=in
  1287.     fi
  1288.     
  1289.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1290.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1291.     then
  1292.         client_ports="${LOCAL_CLIENT_PORTS}"
  1293.     fi
  1294.     
  1295.     # For an explanation of how FTP connections work, see
  1296.     # http://slacksite.com/other/ftp.html
  1297.     
  1298.     # ----------------------------------------------------------------------
  1299.     
  1300.     # allow new and established incoming, and established outgoing
  1301.     # accept port ftp new connections
  1302.     set_work_function "Setting up rules for initial FTP connection ${type}"
  1303.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto tcp sport "${client_ports}" dport ftp state NEW,ESTABLISHED || return 1
  1304.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto tcp sport "${client_ports}" dport ftp state ESTABLISHED     || return 1
  1305.     
  1306.     # Active FTP
  1307.     # send port ftp-data related connections
  1308.     set_work_function "Setting up rules for Active FTP ${type}"
  1309.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto tcp sport "${client_ports}" dport ftp-data state ESTABLISHED,RELATED || return 1
  1310.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto tcp sport "${client_ports}" dport ftp-data state ESTABLISHED         || return 1
  1311.     
  1312.     # ----------------------------------------------------------------------
  1313.     
  1314.     # A hack for Passive FTP only
  1315.     local s_client_ports="${DEFAULT_CLIENT_PORTS}"
  1316.     local c_client_ports="${DEFAULT_CLIENT_PORTS}"
  1317.     
  1318.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1319.     then
  1320.         c_client_ports="${LOCAL_CLIENT_PORTS}"
  1321.     elif [ "${type}" = "server" -a "${work_cmd}" = "interface" ]
  1322.     then
  1323.         s_client_ports="${LOCAL_CLIENT_PORTS}"
  1324.     fi
  1325.     
  1326.     # Passive FTP
  1327.     # accept high-ports related connections
  1328.     set_work_function "Setting up rules for Passive FTP ${type}"
  1329.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto tcp sport "${c_client_ports}" dport "${s_client_ports}" state ESTABLISHED,RELATED || return 1
  1330.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto tcp sport "${c_client_ports}" dport "${s_client_ports}" state ESTABLISHED         || return 1
  1331.     
  1332.     require_kernel_module ip_conntrack_ftp
  1333.     test ${FIREHOL_NAT} -eq 1 && require_kernel_module ip_nat_ftp
  1334.     
  1335.     return 0
  1336. }
  1337.  
  1338.  
  1339. # --- TFTP ---------------------------------------------------------------------
  1340. # Written by: Goetz Bock <bock@blacknet.de>
  1341.  
  1342. rules_tftp() {
  1343.     local mychain="${1}"; shift
  1344.     local type="${1}"; shift
  1345.     
  1346.     local in=in
  1347.     local out=out
  1348.     if [ "${type}" = "client" ]
  1349.     then
  1350.         in=out
  1351.         out=in
  1352.     fi
  1353.     
  1354.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1355.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1356.     then
  1357.         client_ports="${LOCAL_CLIENT_PORTS}"
  1358.     fi
  1359.     
  1360.     # ---------------------------------------------------------------------
  1361.     # TFTP is a broken protokol. It works like this:
  1362.     #
  1363.     # 1. The client sends from a high port (a) to the server's tftp port an
  1364.     #    udp packet with "give me file 'bla'".
  1365.     #
  1366.     # 2. The server replies from a high port (b) to the highport the client
  1367.     #    used (a) with "this is part 0 if your file"
  1368.     #
  1369.     # 3. The client now has to send a reply (from his highport a) to the
  1370.     #    servers high port (b): "got part 0, send next part 1".
  1371.     #
  1372.     # 4. repeat 2. and 3. till file transmitted
  1373.     
  1374.     # allow the initial TFTP connection
  1375.     set_work_function "Setting up rules for initial TFTP connection (${type})"
  1376.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport "${client_ports}" dport tftp state NEW,ESTABLISHED || return 1
  1377. #    rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport "${client_ports}" dport tftp state ESTABLISHED     || return 1
  1378.     
  1379.     # We now need both server and client port ranges
  1380.     local s_client_ports="${DEFAULT_CLIENT_PORTS}"
  1381.     local c_client_ports="${DEFAULT_CLIENT_PORTS}"
  1382.     
  1383.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1384.     then
  1385.         c_client_ports="${LOCAL_CLIENT_PORTS}"
  1386.     elif [ "${type}" = "server" -a "${work_cmd}" = "interface" ]
  1387.     then
  1388.         s_client_ports="${LOCAL_CLIENT_PORTS}"
  1389.     fi
  1390.     
  1391.     # allow the TFTP server to establish a new connection to the client
  1392.     set_work_function "Setting up rules for server-to-client TFTP connection (${type})"
  1393.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "udp" sport "${c_client_ports}" dport "${s_client_ports}" state RELATED,ESTABLISHED || return 1
  1394.     rule ${in}          action "$@" chain "${in}_${mychain}"  proto "udp" sport "${c_client_ports}" dport "${s_client_ports}" state ESTABLISHED         || return 1
  1395.     
  1396.     require_kernel_module ip_conntrack_tftp
  1397.     test ${FIREHOL_NAT} -eq 1 && require_kernel_module ip_nat_tftp
  1398.     
  1399.     return 0
  1400. }
  1401.  
  1402.  
  1403. # --- PING ---------------------------------------------------------------------
  1404.  
  1405. rules_ping() {
  1406.         local mychain="${1}"; shift
  1407.     local type="${1}"; shift
  1408.     
  1409.     local in=in
  1410.     local out=out
  1411.     if [ "${type}" = "client" ]
  1412.     then
  1413.         in=out
  1414.         out=in
  1415.     fi
  1416.     
  1417.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1418.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1419.     then
  1420.         client_ports="${LOCAL_CLIENT_PORTS}"
  1421.     fi
  1422.     
  1423.     # ----------------------------------------------------------------------
  1424.     
  1425.     # allow incoming new and established PING packets
  1426.     rule ${in} action "$@" chain "${in}_${mychain}" proto icmp custom "--icmp-type echo-request" state NEW,ESTABLISHED || return 1
  1427.     
  1428.     # allow outgoing established packets
  1429.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto icmp custom "--icmp-type echo-reply" state ESTABLISHED || return 1
  1430.     
  1431.     return 0
  1432. }
  1433.  
  1434. # --- TIMESTAMP ----------------------------------------------------------------
  1435.  
  1436. rules_timestamp() {
  1437.         local mychain="${1}"; shift
  1438.     local type="${1}"; shift
  1439.     
  1440.     local in=in
  1441.     local out=out
  1442.     if [ "${type}" = "client" ]
  1443.     then
  1444.         in=out
  1445.         out=in
  1446.     fi
  1447.     
  1448.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1449.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1450.     then
  1451.         client_ports="${LOCAL_CLIENT_PORTS}"
  1452.     fi
  1453.     
  1454.     # ----------------------------------------------------------------------
  1455.     
  1456.     # allow incoming new and established PING packets
  1457.     rule ${in} action "$@" chain "${in}_${mychain}" proto icmp custom "--icmp-type timestamp-request" state NEW,ESTABLISHED || return 1
  1458.     
  1459.     # allow outgoing established packets
  1460.     rule ${out} reverse action "$@" chain "${out}_${mychain}" proto icmp custom "--icmp-type timestamp-reply" state ESTABLISHED || return 1
  1461.     
  1462.     return 0
  1463. }
  1464.  
  1465.  
  1466. # --- P2P ----------------------------------------------------------------------
  1467.  
  1468. rules_p2p() {
  1469.         local mychain="${1}"; shift
  1470.     local type="${1}"; shift
  1471.     
  1472.     local in=in
  1473.     local out=out
  1474.     if [ "${type}" = "client" ]
  1475.     then
  1476.         in=out
  1477.         out=in
  1478.     fi
  1479.     
  1480.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1481.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1482.     then
  1483.         client_ports="${LOCAL_CLIENT_PORTS}"
  1484.     fi
  1485.     
  1486.     # ----------------------------------------------------------------------
  1487.     
  1488.     # Remove the action from the arguments.
  1489.     shift
  1490.     
  1491.     do_in() {
  1492.         # allow new and established incoming packets
  1493.         rule ${in} action "$@" chain "${in}_${mychain}" state NEW,ESTABLISHED || return 1
  1494.     }
  1495.     
  1496.     do_out() {
  1497.         # allow outgoing established packets
  1498.         rule ${out} reverse action "$@" chain "${out}_${mychain}" state NEW,ESTABLISHED || return 1
  1499.     }
  1500.     
  1501.     # Kazaa
  1502.     # Check: http://www.derkeiler.com/Mailing-Lists/Firewall-Wizards/2003-06/0152.html
  1503.     # New clients will try to use port 80 - use a proxy to filter this too.
  1504.     set_work_function "Setting up rules for Kazaa (${type})"
  1505.     do_in  drop "$@" proto "tcp udp" sport 1214
  1506.     do_in  drop "$@" proto "tcp udp" dport 1214
  1507.     do_out drop "$@" proto "tcp udp" dport 1214
  1508.     do_out drop "$@" proto "tcp udp" sport 1214
  1509.     
  1510.     # Gnutella
  1511.     
  1512.     # Mldonkey
  1513.     
  1514.     # Emule
  1515.     
  1516.     # audiogalaxy
  1517.     
  1518.     # hotline
  1519.     
  1520.     
  1521.     return 0
  1522. }
  1523.  
  1524.  
  1525. # --- ALL ----------------------------------------------------------------------
  1526.  
  1527. rules_all() {
  1528.         local mychain="${1}"; shift
  1529.     local type="${1}"; shift
  1530.     
  1531.     local in=in
  1532.     local out=out
  1533.     if [ "${type}" = "client" ]
  1534.     then
  1535.         in=out
  1536.         out=in
  1537.     fi
  1538.     
  1539.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1540.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1541.     then
  1542.         client_ports="${LOCAL_CLIENT_PORTS}"
  1543.     fi
  1544.     
  1545.     # ----------------------------------------------------------------------
  1546.     
  1547.     # allow new and established incoming packets
  1548.     rule ${in} action "$@" chain "${in}_${mychain}" state NEW,ESTABLISHED || return 1
  1549.     
  1550.     # allow outgoing established packets
  1551.     rule ${out} reverse action "$@" chain "${out}_${mychain}" state ESTABLISHED || return 1
  1552.     
  1553.     local ser=
  1554.     for ser in ${ALL_SHOULD_ALSO_RUN}
  1555.     do
  1556.         "${type}" ${ser} "$@" || return 1
  1557.     done
  1558.     
  1559.     return 0
  1560. }
  1561.  
  1562.  
  1563. # --- ANY ----------------------------------------------------------------------
  1564.  
  1565. rules_any() {
  1566.         local mychain="${1}"; shift
  1567.     local type="${1}"; shift
  1568.     local name="${1}"; shift # a special case: service any gets a name
  1569.     
  1570.     local in=in
  1571.     local out=out
  1572.     if [ "${type}" = "client" ]
  1573.     then
  1574.         in=out
  1575.         out=in
  1576.     fi
  1577.     
  1578.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1579.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1580.     then
  1581.         client_ports="${LOCAL_CLIENT_PORTS}"
  1582.     fi
  1583.     
  1584.     # ----------------------------------------------------------------------
  1585.     
  1586.     # allow new and established incoming packets
  1587.     rule ${in} action "$@" chain "${in}_${mychain}" state NEW,ESTABLISHED || return 1
  1588.     
  1589.     # allow outgoing established packets
  1590.     rule ${out} reverse action "$@" chain "${out}_${mychain}" state ESTABLISHED || return 1
  1591.     
  1592.     return 0
  1593. }
  1594.  
  1595.  
  1596. # --- ANYSTATELESS -------------------------------------------------------------
  1597.  
  1598. rules_anystateless() {
  1599.         local mychain="${1}"; shift
  1600.     local type="${1}"; shift
  1601.     local name="${1}"; shift # a special case: service any gets a name
  1602.     
  1603.     local in=in
  1604.     local out=out
  1605.     if [ "${type}" = "client" ]
  1606.     then
  1607.         in=out
  1608.         out=in
  1609.     fi
  1610.     
  1611.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1612.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1613.     then
  1614.         client_ports="${LOCAL_CLIENT_PORTS}"
  1615.     fi
  1616.     
  1617.     # ----------------------------------------------------------------------
  1618.     
  1619.     # allow new and established incoming packets
  1620.     rule ${in} action "$@" chain "${in}_${mychain}" || return 1
  1621.     
  1622.     # allow outgoing established packets
  1623.     rule ${out} reverse action "$@" chain "${out}_${mychain}" || return 1
  1624.     
  1625.     return 0
  1626. }
  1627.  
  1628.  
  1629. # --- MULTICAST ----------------------------------------------------------------
  1630.  
  1631. rules_multicast() {
  1632.         local mychain="${1}"; shift
  1633.     local type="${1}"; shift
  1634.     
  1635.     local in=in
  1636.     local out=out
  1637.     if [ "${type}" = "client" ]
  1638.     then
  1639.         in=out
  1640.         out=in
  1641.     fi
  1642.     
  1643.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1644.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1645.     then
  1646.         client_ports="${LOCAL_CLIENT_PORTS}"
  1647.     fi
  1648.     
  1649.     # ----------------------------------------------------------------------
  1650.     
  1651.     # match multicast packets in both directions
  1652.     rule ${out} action "$@" chain "${out}_${mychain}" dst "224.0.0.0/8" proto 2 || return 1
  1653.     rule ${in} reverse action "$@" chain "${in}_${mychain}" src "224.0.0.0/8" proto 2 || return 1
  1654.     
  1655.     return 0
  1656. }
  1657.  
  1658.  
  1659. # --- CUSTOM -------------------------------------------------------------------
  1660.  
  1661. rules_custom() {
  1662.     local mychain="${1}"; shift
  1663.     local type="${1}"; shift
  1664.     
  1665.     local server="${1}"; shift
  1666.     local my_server_ports="${1}"; shift
  1667.     local my_client_ports="${1}"; shift
  1668.     
  1669.     local in=in
  1670.     local out=out
  1671.     if [ "${type}" = "client" ]
  1672.     then
  1673.         in=out
  1674.         out=in
  1675.     fi
  1676.     
  1677.     local client_ports="${DEFAULT_CLIENT_PORTS}"
  1678.     if [ "${type}" = "client" -a "${work_cmd}" = "interface" ]
  1679.     then
  1680.         client_ports="${LOCAL_CLIENT_PORTS}"
  1681.     fi
  1682.     
  1683.     # ----------------------------------------------------------------------
  1684.     
  1685.     local sp=
  1686.     for sp in ${my_server_ports}
  1687.     do
  1688.         local proto=
  1689.         local sport=
  1690.         
  1691.         IFS="/" read proto sport <<EOF
  1692. $sp
  1693. EOF
  1694.         
  1695.         local cp=
  1696.         for cp in ${my_client_ports}
  1697.         do
  1698.             local cport=
  1699.             case ${cp} in
  1700.                 default)
  1701.                     cport="${client_ports}"
  1702.                     ;;
  1703.                     
  1704.                 *)    cport="${cp}"
  1705.                     ;;
  1706.             esac
  1707.             
  1708.             # allow new and established incoming packets
  1709.             rule ${in} action "$@" chain "${in}_${mychain}" proto "${proto}" sport "${cport}" dport "${sport}" state NEW,ESTABLISHED || return 1
  1710.             
  1711.             # allow outgoing established packets
  1712.             rule ${out} reverse action "$@" chain "${out}_${mychain}" proto "${proto}" sport "${cport}" dport "${sport}" state ESTABLISHED || return 1
  1713.         done
  1714.     done
  1715.     
  1716.     return 0
  1717. }
  1718.  
  1719.  
  1720. # ------------------------------------------------------------------------------
  1721.  
  1722. # The caller may need just our services definitions
  1723. if [ "$1" = "gimme-the-services-defs" ]
  1724. then
  1725.     return 0
  1726.     exit 1
  1727. fi
  1728.  
  1729.  
  1730. # ------------------------------------------------------------------------------
  1731. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  1732. # ------------------------------------------------------------------------------
  1733. #
  1734. # SUPPORT FOR EXTERNAL DEFINITIONS OF SERVICES
  1735. #
  1736. # ------------------------------------------------------------------------------
  1737. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  1738. # ------------------------------------------------------------------------------
  1739.  
  1740. # Load all the services.
  1741. # All these files should start with: #FHVER: 1
  1742. cd "${FIREHOL_CONFIG_DIR}/services" || exit 1
  1743. for f in `ls *.conf 2>/dev/null`
  1744. do
  1745.     cd "${FIREHOL_CONFIG_DIR}/services" || exit 1
  1746.     
  1747.     if [ ! -O "${f}" ]
  1748.     then
  1749.         echo >&2 " >>> Ignoring service in '${FIREHOL_CONFIG_DIR}/services/${f}' because it is not owned by root."
  1750.         continue
  1751.     fi
  1752.     
  1753.     n=`"${HEAD_CMD}" -n 1 "${f}" | "${CUT_CMD}" -d ':' -f 2`
  1754.     "${EXPR_CMD}" ${n} + 0 >/dev/null 2>&1
  1755.     if [ $? -ne 0 ]
  1756.     then
  1757.         echo >&2 " >>> Ignoring service in '${FIREHOL_CONFIG_DIR}/services/${f}' due to malformed header."
  1758.     elif [ ${n} -ne ${FIREHOL_SERVICES_API} ]
  1759.     then
  1760.         echo >&2 " >>> Ignoring service '${FIREHOL_CONFIG_DIR}/services/${f}' due to incompatible API version."
  1761.     else
  1762.         n=`"${HEAD_CMD}" -n 1 "${f}" | "${CUT_CMD}" -d ':' -f 3`
  1763.         "${EXPR_CMD}" ${n} + 0 >/dev/null 2>&1
  1764.         if [ $? -ne 0 ]
  1765.         then
  1766.             echo >&2 " >>> Ignoring service in '${FIREHOL_CONFIG_DIR}/services/${f}' due to malformed API minor number."
  1767.         else
  1768.             if [ ${n} -gt ${FIREHOL_MINOR_VERSION} ]
  1769.             then
  1770.                 echo >&2 " >>> Ignoring service in '${FIREHOL_CONFIG_DIR}/services/${f}' because the required MINOR version (${n}) is higher than the one provided by FireHOL (${FIREHOL_MINOR_VERSION})."
  1771.             else
  1772.                 source ${f}
  1773.                 ret=$?
  1774.                 if [ ${ret} -ne 0 ]
  1775.                 then
  1776.                     echo >&2 " >>> Service in '${FIREHOL_CONFIG_DIR}/services/${f}' returned code ${ret}."
  1777.                     continue
  1778.                 fi
  1779.             fi
  1780.         fi
  1781.     fi
  1782. done
  1783. cd "${FIREHOL_DEFAULT_WORKING_DIRECTORY}" || exit 1
  1784.  
  1785.  
  1786. # ------------------------------------------------------------------------------
  1787. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  1788. # ------------------------------------------------------------------------------
  1789. #
  1790. # HELPER FUNCTIONS BELLOW THIS POINT
  1791. #
  1792. # ------------------------------------------------------------------------------
  1793. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  1794. # ------------------------------------------------------------------------------
  1795.  
  1796. # Fetch a URL and output it to the standard output.
  1797. firehol_wget() {
  1798.     local url="${1}"
  1799.     
  1800.     require_cmd wget curl || error "Cannot find 'wget' or 'curl' in the path."
  1801.     
  1802.     if [ ! -z "${WGET_CMD}" ]
  1803.     then
  1804.         ${WGET_CMD} -O - "${url}" 2>/dev/null
  1805.         return $?
  1806.     elif [ ! -z "${CURL_CMD}" ]
  1807.     then
  1808.         ${CURL_CMD} -s "${url}"
  1809.         return $?
  1810.     fi
  1811.     
  1812.     error "Cannot use either 'wget' or 'curl' to fetch '${url}'."
  1813.     return 1
  1814. }
  1815.  
  1816. FIREHOL_ECN_SHAME_URL="http://urchin.earth.li/cgi-bin/ecn.pl?output=ip"
  1817. ecn_shame() {
  1818.     work_realcmd_helper ${FUNCNAME} "$@"
  1819.     
  1820.     set_work_function -ne "Initializing $FUNCNAME"
  1821.     
  1822.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  1823.     
  1824.     if [ `${CAT_CMD} /proc/sys/net/ipv4/tcp_ecn` -eq 1 ]
  1825.     then
  1826.         set_work_function "Fetching '${FIREHOL_ECN_SHAME_URL}'."
  1827.         
  1828.         # Reads in list of ip address and makes iptables rules to drop ecn
  1829.         # from packets destined for those hosts.
  1830.         # http://urchin.earth.li/ecn/
  1831.         
  1832.         local tmp="${FIREHOL_DIR}/ecn_shame.ips"
  1833.         
  1834.         firehol_wget "${FIREHOL_ECN_SHAME_URL}" | ${SORT_CMD} | ${UNIQ_CMD} >"${tmp}"
  1835.         if [ $? -ne 0 -o ! -s "${tmp}" ]
  1836.         then
  1837.             softwarning "Cannot fetch '${FIREHOL_ECN_SHAME_URL}'."
  1838.         else
  1839.             ${MV_CMD} -f "${tmp}" "${FIREHOL_SPOOL_DIR}/ecn_shame.ips"
  1840.         fi
  1841.         
  1842.         set_work_function "Removing ECN for all communication from/to SHAME ECN list."
  1843.         
  1844.         local count=0
  1845.         for ip in `${CAT_CMD} "${FIREHOL_SPOOL_DIR}/ecn_shame.ips"`
  1846.         do
  1847.             local count=$[count + 1]
  1848.             iptables -t mangle -A POSTROUTING -p tcp -d ${ip} -j ECN --ecn-tcp-remove
  1849.         done
  1850.         
  1851.         test ${count} -eq 0 && softwarning "No ECN SHAME IPs found." && return 1
  1852.     else
  1853.         softwarning "TCP_ECN is not enabled in the kernel. ECN_SHAME helper is ignored."
  1854.         return 0
  1855.     fi
  1856.     return 0
  1857. }
  1858.  
  1859. masquerade() {
  1860.     work_realcmd_helper ${FUNCNAME} "$@"
  1861.     
  1862.     set_work_function -ne "Initializing $FUNCNAME"
  1863.     
  1864.     local f="${work_outface}"
  1865.     test "${1}" = "reverse" && f="${work_inface}" && shift
  1866.     
  1867.     test -z "${f}" && local f="${1}" && shift
  1868.     
  1869.     test -z "${f}" && error "masquerade requires an interface set or as argument" && return 1
  1870.     
  1871.     set_work_function "Initializing masquerade on interface '${f}'"
  1872.     
  1873.     rule noowner table nat chain POSTROUTING "$@" inface any outface "${f}" action MASQUERADE || return 1
  1874.     
  1875.     FIREHOL_NAT=1
  1876.     FIREHOL_ROUTING=1
  1877.     
  1878.     return 0
  1879. }
  1880.  
  1881. transparent_proxy_count=0
  1882. transparent_proxy() {
  1883.     work_realcmd_helper $FUNCNAME "$@"
  1884.     
  1885.     set_work_function -ne "Initializing $FUNCNAME"
  1886.     
  1887.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  1888.     
  1889.     local ports="${1}"; shift
  1890.     local redirect="${1}"; shift
  1891.     local user="${1}"; shift
  1892.     
  1893.     test -z "${redirect}" && error "Proxy listening port is empty" && return 1
  1894.     
  1895.     transparent_proxy_count=$[transparent_proxy_count + 1]
  1896.     
  1897.     set_work_function "Setting up rules for catching routed tcp/${ports} traffic"
  1898.     
  1899.     create_chain nat "in_trproxy.${transparent_proxy_count}" PREROUTING noowner "$@" outface any proto tcp sport "${DEFAULT_CLIENT_PORTS}" dport "${ports}" || return 1
  1900. #    rule table nat chain "in_trproxy.${transparent_proxy_count}" proto tcp dport "${ports}" action REDIRECT to-port ${redirect} || return 1
  1901.     rule table nat chain "in_trproxy.${transparent_proxy_count}" proto tcp action REDIRECT to-port ${redirect} || return 1
  1902.     
  1903.     if [ ! -z "${user}" ]
  1904.     then
  1905.         set_work_function "Setting up rules for catching outgoing tcp/${ports} traffic"
  1906.         create_chain nat "out_trproxy.${transparent_proxy_count}" OUTPUT "$@" uid not "${user}" nosoftwarnings inface any outface any src any proto tcp sport "${LOCAL_CLIENT_PORTS}" dport "${ports}" || return 1
  1907.         
  1908.         # do not catch traffic for localhost servers
  1909.         rule table nat chain "out_trproxy.${transparent_proxy_count}" dst "127.0.0.1" action RETURN || return 1
  1910.         
  1911. #        rule table nat chain "out_trproxy.${transparent_proxy_count}" proto tcp dport "${ports}" action REDIRECT to-port ${redirect} || return 1
  1912.         rule table nat chain "out_trproxy.${transparent_proxy_count}" proto tcp action REDIRECT to-port ${redirect} || return 1
  1913.     fi
  1914.     
  1915.     FIREHOL_NAT=1
  1916.     FIREHOL_ROUTING=1
  1917.     
  1918.     return 0
  1919. }
  1920.  
  1921. transparent_squid() {
  1922.     transparent_proxy 80 "$@"
  1923. }
  1924.  
  1925. nat_count=0
  1926. nat_helper() {
  1927. #    work_realcmd_helper $FUNCNAME "$@"
  1928.     
  1929.     set_work_function -ne "Initializing $FUNCNAME"
  1930.     
  1931.     require_work clear || ( error "NAT cannot be used in '${work_cmd}'. Put all NAT related commands before any '${work_cmd}' definition."; return 1 )
  1932.     
  1933.     local type="${1}"; shift
  1934.     local to="${1}";   shift
  1935.     
  1936.     nat_count=$[nat_count + 1]
  1937.     
  1938.     set_work_function -ne "Setting up rules for NAT type: '${type}'"
  1939.     
  1940.     case ${type} in
  1941.         to-source)
  1942.             create_chain nat "nat.${nat_count}" POSTROUTING nolog "$@" inface any || return 1
  1943.             local action=snat
  1944.             ;;
  1945.         
  1946.         to-destination)
  1947.             create_chain nat "nat.${nat_count}" PREROUTING noowner nolog "$@" outface any || return 1
  1948.             local action=dnat
  1949.             ;;
  1950.             
  1951.         redirect-to)
  1952.             create_chain nat "nat.${nat_count}" PREROUTING noowner nolog "$@" outface any || return 1
  1953.             local action=redirect
  1954.             ;;
  1955.             
  1956.         *)
  1957.             error "$FUNCNAME requires a type (i.e. to-source, to-destination, redirect-to, etc) as its first argument. '${type}' is not understood."
  1958.             return 1
  1959.             ;;
  1960.     esac
  1961.     
  1962.     
  1963.     set_work_function "Taking the NAT action: '${action}'"
  1964.     
  1965.     # we now need to keep the protocol
  1966.     rule table nat chain "nat.${nat_count}" noowner "$@" action "${action}" to "${to}" nosoftwarnings src any dst any inface any outface any sport any dport any || return 1
  1967.     
  1968.     FIREHOL_NAT=1
  1969.     FIREHOL_ROUTING=1
  1970.     
  1971.     return 0
  1972. }
  1973.  
  1974. nat() {
  1975.     work_realcmd_helper $FUNCNAME "$@"
  1976.     
  1977.     set_work_function -ne "Initializing $FUNCNAME"
  1978.     
  1979.     nat_helper "$@"
  1980. }
  1981.  
  1982. snat() {
  1983.     work_realcmd_helper $FUNCNAME "$@"
  1984.     
  1985.     set_work_function -ne "Initializing $FUNCNAME"
  1986.     
  1987.     local to="${1}"; shift
  1988.     test "${to}" = "to" && local to="${1}" && shift
  1989.     
  1990.     nat_helper "to-source" "${to}" "$@"
  1991. }
  1992.  
  1993. dnat() {
  1994.     work_realcmd_helper $FUNCNAME "$@"
  1995.     
  1996.     set_work_function -ne "Initializing $FUNCNAME"
  1997.     
  1998.     local to="${1}"; shift
  1999.     test "${to}" = "to" && local to="${1}" && shift
  2000.     
  2001.     nat_helper "to-destination" "${to}" "$@"
  2002. }
  2003.  
  2004. redirect() {
  2005.     work_realcmd_helper $FUNCNAME "$@"
  2006.     
  2007.     set_work_function -ne "Initializing $FUNCNAME"
  2008.     
  2009.     local to="${1}"; shift
  2010.     test "${to}" = "to" -o "${to}" = "to-port" && local to="${1}" && shift
  2011.     
  2012.     nat_helper "redirect-to" "${to}" "$@"
  2013. }
  2014.  
  2015. wrongmac_chain=0
  2016. mac() {
  2017.     work_realcmd_helper $FUNCNAME "$@"
  2018.     
  2019.     set_work_function -ne "Initializing $FUNCNAME"
  2020.     
  2021.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  2022.     
  2023.     if [ ${wrongmac_chain} -eq 0 ]
  2024.     then
  2025.         set_work_function "Creating the MAC-MISSMATCH chain (only once)"
  2026.         
  2027.         iptables -t filter -N WRONGMAC
  2028.         rule table filter chain WRONGMAC loglimit "MAC MISSMATCH" action DROP || return 1
  2029.         
  2030.         wrongmac_chain=1
  2031.     fi
  2032.     
  2033.     set_work_function "If the source IP ${1} does not match MAC ${2}, drop the packet"
  2034.     
  2035.     iptables -t filter -A INPUT   -s "${1}" -m mac --mac-source ! "${2}" -j WRONGMAC
  2036.     iptables -t filter -A FORWARD -s "${1}" -m mac --mac-source ! "${2}" -j WRONGMAC
  2037.     
  2038.     return 0
  2039. }
  2040.  
  2041. # blacklist creates two types of blacklists: unidirectional or bidirectional
  2042. blacklist_chain=0
  2043. blacklist() {
  2044.     work_realcmd_helper ${FUNCNAME} "$@"
  2045.     
  2046.     set_work_function -ne "Initializing $FUNCNAME"
  2047.     
  2048.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  2049.     
  2050.     local full=1
  2051.     if [ "${1}" = "them" -o "${1}" = "him" -o "${1}" = "her" -o "${1}" = "it" -o "${1}" = "this" -o "${1}" = "these"  -o "${1}" = "input" ]
  2052.     then
  2053.         shift
  2054.         full=0
  2055.     elif [ "${1}" = "all" -o "${1}" = "full" ]
  2056.     then
  2057.         shift
  2058.         full=1
  2059.     fi
  2060.     
  2061.     if [ ${blacklist_chain} -eq 0 ]
  2062.     then
  2063.         set_work_function "Generating blacklist chains"
  2064.         
  2065.         # Blacklist INPUT unidirectional
  2066.         iptables -t filter -N BL_IN_UNI    # INPUT
  2067.         iptables -A BL_IN_UNI -m state --state NEW -j DROP
  2068.         
  2069.         # No need for OUTPUT/FORWARD unidirectional
  2070.         
  2071.         # Blacklist INPUT bidirectional
  2072.         iptables -t filter -N BL_IN_BI    # INPUT
  2073.         iptables -A BL_IN_BI -j DROP
  2074.         
  2075.         # Blacklist OUTPUT/FORWARD bidirectional
  2076.         iptables -t filter -N BL_OUT_BI    # OUTPUT and FORWARD
  2077.         iptables -A BL_OUT_BI -p tcp -j REJECT --reject-with tcp-reset
  2078.         iptables -A BL_OUT_BI -j REJECT --reject-with icmp-host-unreachable
  2079.         
  2080.         blacklist_chain=1
  2081.     fi
  2082.     
  2083.     set_work_function "Generating blacklist rules"
  2084.     
  2085.     local z=
  2086.     for z in $@
  2087.     do
  2088.         local x=
  2089.         for x in ${z}
  2090.         do
  2091.             set_work_function "Blacklisting '${x}'"
  2092.             
  2093.             if [ ${full} -eq 1 ]
  2094.             then
  2095.                 iptables -I INPUT   -s ${x} -j BL_IN_BI
  2096.                 iptables -I FORWARD -s ${x} -j BL_IN_BI
  2097.                 
  2098.                 iptables -I OUTPUT  -d ${x} -j BL_OUT_BI
  2099.                 iptables -I FORWARD -d ${x} -j BL_OUT_BI  
  2100.             else
  2101.                 iptables -I INPUT   -s ${x} -j BL_IN_UNI
  2102.                 iptables -I FORWARD -s ${x} -j BL_IN_UNI
  2103.             fi
  2104.         done
  2105.     done
  2106.     
  2107.     return 0
  2108. }
  2109.  
  2110. mark_count=0
  2111. mark() {
  2112.     work_realcmd_helper $FUNCNAME "$@"
  2113.     
  2114.     set_work_function -ne "Initializing $FUNCNAME"
  2115.     
  2116.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  2117.     
  2118.     local num="${1}"; shift
  2119.     local where="${1}"; shift
  2120.     test -z "${where}" && where=OUTPUT
  2121.     
  2122.     mark_count=$[mark_count + 1]
  2123.     
  2124.     set_work_function "Setting up rules for MARK"
  2125.     
  2126.     create_chain mangle "mark.${mark_count}" "${where}" "$@" || return 1
  2127.     iptables -t mangle -A "mark.${mark_count}" -j MARK --set-mark ${num}
  2128.     
  2129.     return 0
  2130. }
  2131.  
  2132. tos_count=0
  2133. tos() {
  2134.     work_realcmd_helper $FUNCNAME "$@"
  2135.     
  2136.     set_work_function -ne "Initializing $FUNCNAME"
  2137.     
  2138.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  2139.     
  2140.     local num="${1}"; shift
  2141.     local where="${1}"; shift
  2142.     test -z "${where}" && where=OUTPUT
  2143.     
  2144.     tos_count=$[tos_count + 1]
  2145.     
  2146.     set_work_function "Setting up rules for TOS"
  2147.     
  2148.     create_chain mangle "tos.${tos_count}" "${where}" "$@" || return 1
  2149.     iptables -t mangle -A "tos.${tos_count}" -j TOS --set-tos ${num}
  2150.     
  2151.     return 0
  2152. }
  2153.  
  2154. dscp_count=0
  2155. dscp() {
  2156.     work_realcmd=($FUNCNAME "$@")
  2157.     
  2158.     set_work_function -ne "Initializing $FUNCNAME"
  2159.     
  2160.     require_work clear || ( error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition."; return 1 )
  2161.     
  2162.     local value="${1}"; shift
  2163.     local class=""
  2164.     
  2165.     if [ "${value}" = "class" ]
  2166.     then
  2167.         local value=""
  2168.         local class="${1}"; shift
  2169.     fi
  2170.     
  2171.     local where="${1}"; shift
  2172.     test -z "${where}" && where=OUTPUT
  2173.     
  2174.     dscp_count=$[dscp_count + 1]
  2175.     
  2176.     set_work_function "Setting up rules for setting DSCP"
  2177.     
  2178.     create_chain mangle "dscp.${dscp_count}" "${where}" "$@" || return 1
  2179.     
  2180.     if [ ! -z "${class}" ]
  2181.     then
  2182.         iptables -t mangle -A "dscp.${dscp_count}" -j DSCP --set-dscp-class ${class}
  2183.     else
  2184.         iptables -t mangle -A "dscp.${dscp_count}" -j DSCP --set-dscp ${value}
  2185.     fi
  2186.     
  2187.     return 0
  2188. }
  2189.  
  2190. tcpmss() {
  2191.     work_realcmd_helper $FUNCNAME "$@"
  2192.     
  2193.     set_work_function -ne "Initializing $FUNCNAME"
  2194.     
  2195.     # work only if this helper is called before any primary command
  2196.     # or within routers.
  2197.     if [ -z "${work_cmd}" -o "${work_cmd}" = "router" ]
  2198.     then
  2199.         local chains="FORWARD"
  2200.         
  2201.         test ! -z "${work_cmd}" && chains="in_${work_name} out_${work_name}"
  2202.         
  2203.         for tcmpmss_chain in ${chains}
  2204.         do
  2205.             case $1 in
  2206.                 auto)
  2207.                     iptables -A "${tcmpmss_chain}" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
  2208.                     ;;
  2209.                     
  2210.                 [0-9]*)
  2211.                     iptables -A "${tcmpmss_chain}" -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $1
  2212.                     ;;
  2213.                 
  2214.                 *)
  2215.                     error "$FUNCNAME requires either the word 'auto' or a numeric argument."
  2216.                     return 1
  2217.                     ;;
  2218.             esac
  2219.         done
  2220.     else
  2221.         error "$FUNCNAME cannot be used in '${work_cmd}'. Put it before any '${work_cmd}' definition or in 'router' definitions."
  2222.         return 1
  2223.     fi
  2224.     
  2225.     return 0
  2226. }
  2227.  
  2228.  
  2229. # ------------------------------------------------------------------------------
  2230. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2231. # ------------------------------------------------------------------------------
  2232. #
  2233. # INTERNAL FUNCTIONS BELLOW THIS POINT - Primary commands
  2234. #
  2235. # ------------------------------------------------------------------------------
  2236. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2237. # ------------------------------------------------------------------------------
  2238.  
  2239.  
  2240. # ------------------------------------------------------------------------------
  2241. # Check the version required by the configuration file
  2242. # WHY:
  2243. # We have to make sure the configuration file has been written for this version
  2244. # of FireHOL. Note that the version command does not actually check the version
  2245. # of firehol.sh. It checks only its release number (R5 currently).
  2246.  
  2247. version() {
  2248.         work_realcmd_helper ${FUNCNAME} "$@"
  2249.     
  2250.     if [ ${1} -gt ${FIREHOL_VERSION} ]
  2251.     then
  2252.         error "Wrong version. FireHOL is v${FIREHOL_VERSION}, your script requires v${1}."
  2253.     fi
  2254. }
  2255.  
  2256.  
  2257. # ------------------------------------------------------------------------------
  2258. # PRIMARY COMMAND: interface
  2259. # Setup rules specific to an interface (physical or logical)
  2260.  
  2261. interface() {
  2262.         work_realcmd_primary ${FUNCNAME} "$@"
  2263.     
  2264.     # --- close any open command ---
  2265.     
  2266.     close_cmd || return 1
  2267.     
  2268.     
  2269.     # --- test prerequisites ---
  2270.     
  2271.     require_work clear || return 1
  2272.     set_work_function -ne "Initializing $FUNCNAME"
  2273.     
  2274.     
  2275.     # --- get paramaters and validate them ---
  2276.     
  2277.     # Get the interface
  2278.     local inface="${1}"; shift
  2279.     test -z "${inface}" && error "real interface is not set" && return 1
  2280.     
  2281.     # Get the name for this interface
  2282.     local name="${1}"; shift
  2283.     test -z "${name}" && error "$FUNCNAME name is not set" && return 1
  2284.     
  2285.     
  2286.     # --- do the job ---
  2287.     
  2288.     work_cmd="${FUNCNAME}"
  2289.     work_name="${name}"
  2290.     work_realcmd=("(unset)")
  2291.     
  2292.     set_work_function -ne "Initializing $FUNCNAME '${work_name}'"
  2293.     
  2294.     create_chain filter "in_${work_name}" INPUT in set_work_inface "$@" inface "${inface}" outface any || return 1
  2295.     create_chain filter "out_${work_name}" OUTPUT out set_work_outface reverse "$@" inface "${inface}" outface any || return 1
  2296.     
  2297.     return 0
  2298. }
  2299.  
  2300.  
  2301. router() {
  2302.         work_realcmd_helper ${FUNCNAME} "$@"
  2303.     
  2304.     # --- close any open command ---
  2305.     
  2306.     close_cmd || return 1
  2307.     
  2308.     
  2309.     # --- test prerequisites ---
  2310.     
  2311.     require_work clear || return 1
  2312.     set_work_function -ne "Initializing $FUNCNAME"
  2313.     
  2314.     
  2315.     # --- get paramaters and validate them ---
  2316.     
  2317.     # Get the name for this router
  2318.     local name="${1}"; shift
  2319.     test -z "${name}" && error "$FUNCNAME name is not set" && return 1
  2320.     
  2321.     
  2322.     # --- do the job ---
  2323.     
  2324.     work_cmd="${FUNCNAME}"
  2325.     work_name="${name}"
  2326.     work_realcmd=("(unset)")
  2327.     
  2328.     set_work_function -ne "Initializing $FUNCNAME '${work_name}'"
  2329.     
  2330.     create_chain filter "in_${work_name}" FORWARD in set_work_inface set_work_outface "$@" || return 1
  2331.     create_chain filter "out_${work_name}" FORWARD out reverse "$@" || return 1
  2332.     
  2333.     FIREHOL_ROUTING=1
  2334.     
  2335.     return 0
  2336. }
  2337.  
  2338. postprocess() {
  2339. #       work_realcmd_helper ${FUNCNAME} "$@"
  2340.     
  2341.     local check="error"
  2342.     test "A${1}" = "A-ne"   && shift && local check="none"
  2343.     test "A${1}" = "A-warn" && shift && local check="warn"
  2344.     
  2345.     test ${FIREHOL_DEBUG}   -eq 1 && local check="none"
  2346.     test ${FIREHOL_EXPLAIN} -eq 1 && local check="none"
  2347.     
  2348.     if [ ! ${check} = "none" ]
  2349.     then
  2350.         printf "runcmd '${check}' '${FIREHOL_LINEID}' " >>${FIREHOL_OUTPUT}
  2351.     fi
  2352.     
  2353.     printf "%q " "$@" >>${FIREHOL_OUTPUT}
  2354.     printf "\n" >>${FIREHOL_OUTPUT}
  2355.     
  2356.     if [ ${FIREHOL_EXPLAIN} -eq 1 ]
  2357.     then
  2358.         ${CAT_CMD} ${FIREHOL_OUTPUT}
  2359.         ${RM_CMD} -f ${FIREHOL_OUTPUT}
  2360.     fi
  2361.     
  2362.     return 0
  2363. }
  2364.  
  2365. runcmd() {
  2366.     local check="${1}"; shift
  2367.     local line="${1}"; shift
  2368.     local cmd="${1}"; shift
  2369.     
  2370.     "${cmd}" "$@" >${FIREHOL_OUTPUT}.log 2>&1
  2371.     local r=$?
  2372.     test ${r} -gt 0 && runtime_error ${check} ${r} ${line} "${cmd}" "$@"
  2373.     
  2374.     return 0
  2375. }
  2376.  
  2377. FIREHOL_COMMAND_COUNTER=0
  2378. iptables() {
  2379. #       work_realcmd_helper ${FUNCNAME} "$@"
  2380.     
  2381.     postprocess "${IPTABLES_CMD}" "$@"
  2382.     FIREHOL_COMMAND_COUNTER=$[FIREHOL_COMMAND_COUNTER + 1]
  2383.     
  2384.     return 0
  2385. }
  2386.  
  2387.  
  2388. # ------------------------------------------------------------------------------
  2389. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2390. # ------------------------------------------------------------------------------
  2391. #
  2392. # INTERNAL FUNCTIONS BELLOW THIS POINT - Sub-commands
  2393. #
  2394. # ------------------------------------------------------------------------------
  2395. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2396. # ------------------------------------------------------------------------------
  2397.  
  2398.  
  2399. # ------------------------------------------------------------------------------
  2400. # Change the policy of an interface
  2401. # WHY:
  2402. # Not all interfaces have the same policy. The admin must have control over it.
  2403. # Here we just set what the admin wants. At the interface finalization we
  2404. # produce the iptables rules.
  2405.  
  2406. policy() {
  2407.         work_realcmd_secondary ${FUNCNAME} "$@"
  2408.     
  2409.     require_work set interface || return 1
  2410.     
  2411.     set_work_function "Setting interface '${work_inface}' (${work_name}) policy to ${1}"
  2412.     work_policy="$*"
  2413.     
  2414.     return 0
  2415. }
  2416.  
  2417. server() {
  2418.     work_realcmd_secondary ${FUNCNAME} "$@"
  2419.     
  2420.     require_work set any || return 1
  2421.     smart_function server "$@"
  2422.     return $?
  2423. }
  2424.  
  2425. client() {
  2426.         work_realcmd_secondary ${FUNCNAME} "$@"
  2427.     
  2428.     require_work set any || return 1
  2429.     smart_function client "$@"
  2430.     return $?
  2431. }
  2432.  
  2433. route() {
  2434.         work_realcmd_secondary ${FUNCNAME} "$@"
  2435.     
  2436.     require_work set router || return 1
  2437.     smart_function server "$@"
  2438.     return $?
  2439. }
  2440.  
  2441.  
  2442. # --- protection ---------------------------------------------------------------
  2443.  
  2444. protection() {
  2445.         work_realcmd_secondary ${FUNCNAME} "$@"
  2446.     
  2447.     require_work set any || return 1
  2448.     
  2449.     local in="in"
  2450.     local prface="${work_inface}"
  2451.     
  2452.     local pre="pr"
  2453.     local reverse=
  2454.     if [ "${1}" = "reverse" ]
  2455.     then
  2456.         local reverse="reverse"    # needed to recursion
  2457.         local pre="prr"        # in case a router has protections
  2458.                     # both ways, the second needs to
  2459.                     # have different chain names
  2460.                     
  2461.         local in="out"        # reverse the interface
  2462.         
  2463.         prface="${work_outface}"
  2464.         shift
  2465.     fi
  2466.     
  2467.     local type="${1}"
  2468.     local rate="${2}"
  2469.     local burst="${3}"
  2470.     
  2471.     test -z "${rate}"  && rate="100/s"
  2472.     test -z "${burst}" && burst="50"
  2473.     
  2474.     set_work_function -ne "Generating protections on '${prface}' for ${work_cmd} '${work_name}'"
  2475.     
  2476.     local x=
  2477.     for x in ${type}
  2478.     do
  2479.         case "${x}" in
  2480.             none|NONE)
  2481.                 return 0
  2482.                 ;;
  2483.             
  2484.             strong|STRONG|full|FULL|all|ALL)
  2485.                 protection ${reverse} "invalid fragments new-tcp-w/o-syn icmp-floods syn-floods malformed-xmas malformed-null malformed-bad" "${rate}" "${burst}"
  2486.                 return $?
  2487.                 ;;
  2488.                 
  2489.             invalid|INVALID)
  2490.                 iptables -A "${in}_${work_name}" -m state --state INVALID -j DROP                || return 1
  2491.                 ;;
  2492.                 
  2493.             fragments|FRAGMENTS)
  2494.                 local mychain="${pre}_${work_name}_fragments"
  2495.                 create_chain filter "${mychain}" "${in}_${work_name}" in custom "-f"                || return 1
  2496.                 
  2497.                 set_work_function "Generating rules to be protected from packet fragments on '${prface}' for ${work_cmd} '${work_name}'"
  2498.                 
  2499.                 rule in chain "${mychain}" loglimit "PACKET FRAGMENTS" action drop                 || return 1
  2500.                 ;;
  2501.                 
  2502.             new-tcp-w/o-syn|NEW-TCP-W/O-SYN)
  2503.                 local mychain="${pre}_${work_name}_nosyn"
  2504.                 create_chain filter "${mychain}" "${in}_${work_name}" in proto tcp state NEW custom "! --syn"    || return 1
  2505.                 
  2506.                 set_work_function "Generating rules to be protected from new TCP connections without the SYN flag set on '${prface}' for ${work_cmd} '${work_name}'"
  2507.                 
  2508.                 rule in chain "${mychain}" loglimit "NEW TCP w/o SYN" action drop                || return 1
  2509.                 ;;
  2510.                 
  2511.             icmp-floods|ICMP-FLOODS)
  2512.                 local mychain="${pre}_${work_name}_icmpflood"
  2513.                 create_chain filter "${mychain}" "${in}_${work_name}" in proto icmp custom "--icmp-type echo-request"    || return 1
  2514.                 
  2515.                 set_work_function "Generating rules to be protected from ICMP floods on '${prface}' for ${work_cmd} '${work_name}'"
  2516.                 
  2517.                 rule in chain "${mychain}" limit "${rate}" "${burst}" action return                || return 1
  2518.                 rule in chain "${mychain}" loglimit "ICMP FLOOD" action drop                    || return 1
  2519.                 ;;
  2520.                 
  2521.             syn-floods|SYN-FLOODS)
  2522.                 local mychain="${pre}_${work_name}_synflood"
  2523.                 create_chain filter "${mychain}" "${in}_${work_name}" in proto tcp custom "--syn"        || return 1
  2524.                 
  2525.                 set_work_function "Generating rules to be protected from TCP SYN floods on '${prface}' for ${work_cmd} '${work_name}'"
  2526.                 
  2527.                 rule in chain "${mychain}" limit "${rate}" "${burst}" action return                || return 1
  2528.                 rule in chain "${mychain}" loglimit "SYN FLOOD" action drop                    || return 1
  2529.                 ;;
  2530.                 
  2531.             malformed-xmas|MALFORMED-XMAS)
  2532.                 local mychain="${pre}_${work_name}_malxmas"
  2533.                 create_chain filter "${mychain}" "${in}_${work_name}" in proto tcp custom "--tcp-flags ALL ALL"    || return 1
  2534.                 
  2535.                 set_work_function "Generating rules to be protected from packets with all TCP flags set on '${prface}' for ${work_cmd} '${work_name}'"
  2536.                 
  2537.                 rule in chain "${mychain}" loglimit "MALFORMED XMAS" action drop                || return 1
  2538.                 ;;
  2539.                 
  2540.             malformed-null|MALFORMED-NULL)
  2541.                 local mychain="${pre}_${work_name}_malnull"
  2542.                 create_chain filter "${mychain}" "${in}_${work_name}" in proto tcp custom "--tcp-flags ALL NONE" || return 1
  2543.                 
  2544.                 set_work_function "Generating rules to be protected from packets with all TCP flags unset on '${prface}' for ${work_cmd} '${work_name}'"
  2545.                 
  2546.                 rule in chain "${mychain}" loglimit "MALFORMED NULL" action drop                || return 1
  2547.                 ;;
  2548.                 
  2549.             malformed-bad|MALFORMED-BAD)
  2550.                 local mychain="${pre}_${work_name}_malbad"
  2551.                 create_chain filter "${mychain}" "${in}_${work_name}" in proto tcp custom "--tcp-flags SYN,FIN SYN,FIN"            || return 1
  2552.                 
  2553.                 set_work_function "Generating rules to be protected from packets with illegal TCP flags on '${prface}' for ${work_cmd} '${work_name}'"
  2554.                 
  2555.                 rule in chain "${in}_${work_name}" action "${mychain}"   proto tcp custom "--tcp-flags SYN,RST SYN,RST"            || return 1
  2556.                 rule in chain "${in}_${work_name}" action "${mychain}"   proto tcp custom "--tcp-flags ALL     SYN,RST,ACK,FIN,URG"    || return 1
  2557.                 rule in chain "${in}_${work_name}" action "${mychain}"   proto tcp custom "--tcp-flags ALL     FIN,URG,PSH"        || return 1
  2558.                 
  2559.                 rule in chain "${mychain}" loglimit "MALFORMED BAD" action drop                                || return 1
  2560.                 ;;
  2561.                 
  2562.             *)
  2563.                 error "Protection '${x}' does not exists."
  2564.                 return 1
  2565.                 ;;
  2566.         esac
  2567.     done
  2568.     
  2569.     return 0
  2570. }
  2571.  
  2572.  
  2573. # ------------------------------------------------------------------------------
  2574. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2575. # ------------------------------------------------------------------------------
  2576. #
  2577. # KERNEL MODULE MANAGEMENT
  2578. #
  2579. # ------------------------------------------------------------------------------
  2580. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2581. # ------------------------------------------------------------------------------
  2582.  
  2583. # ------------------------------------------------------------------------------
  2584. # Manage kernel modules
  2585. # WHY:
  2586. # We need to load a set of kernel modules during postprocessing, and after the
  2587. # new firewall has been activated. Here we just keep a list of the required
  2588. # kernel modules.
  2589.  
  2590. # optionaly require command gzcat
  2591. require_cmd gzcat
  2592.  
  2593. KERNEL_CONFIG=
  2594. if [ -f "/proc/config" ]
  2595. then
  2596.     KERNEL_CONFIG="/proc/config"
  2597.     ${CAT_CMD} /proc/config >${FIREHOL_DIR}/kcfg
  2598.     source ${FIREHOL_DIR}/kcfg
  2599.     ${RM_CMD} -f ${FIREHOL_DIR}/kcfg    
  2600. elif [ -f "/proc/config.gz" -a ! -z "${GZCAT_CMD}" ]
  2601. then
  2602.     KERNEL_CONFIG="/proc/config.gz"
  2603.     ${GZCAT_CMD} /proc/config.gz >${FIREHOL_DIR}/kcfg
  2604.     source ${FIREHOL_DIR}/kcfg
  2605.     ${RM_CMD} -f ${FIREHOL_DIR}/kcfg
  2606.     
  2607. elif [ -f "/lib/modules/`${UNAME_CMD} -r`/build/.config" ]
  2608. then
  2609.     KERNEL_CONFIG="/lib/modules/`${UNAME_CMD} -r`/build/.config"
  2610.     . "${KERNEL_CONFIG}"
  2611.     
  2612. elif [ -f "/boot/config-`${UNAME_CMD} -r`" ]
  2613. then
  2614.     KERNEL_CONFIG="/boot/config-`${UNAME_CMD} -r`"
  2615.     . "${KERNEL_CONFIG}"
  2616.     
  2617. elif [ -f "/usr/src/linux/.config" ]
  2618. then
  2619.     KERNEL_CONFIG="/usr/src/linux/.config"
  2620.     . "${KERNEL_CONFIG}"
  2621. else
  2622.     echo >&2 " "
  2623.     echo >&2 " IMPORTANT WARNING:"
  2624.     echo >&2 " ------------------"
  2625.     echo >&2 " FireHOL cannot find your current kernel configuration."
  2626.     echo >&2 " Please, either compile your kernel with /proc/config,"
  2627.     echo >&2 " or make sure there is a valid kernel config in:"
  2628.     echo >&2 " /usr/src/linux/.config"
  2629.     echo >&2 " "
  2630.     echo >&2 " Because of this, FireHOL will simply attempt to load"
  2631.     echo >&2 " all kernel modules for the services used, without"
  2632.     echo >&2 " being able to detect failures."
  2633.     echo >&2 " "
  2634. fi
  2635.  
  2636. # activation-phase command to check for the existance of
  2637. # a kernel configuration directive. It returns:
  2638. # 0 = module is already in the kernel
  2639. # 1 = module can be loaded with modprobe
  2640. # 2 = no info about this module in the kernel
  2641. check_kernel_config() {
  2642.     eval local kcfg="\$${1}"
  2643.     
  2644.     case ${kcfg} in
  2645.         y)    return 0
  2646.             ;;
  2647.         
  2648.         m)    return 1
  2649.             ;;
  2650.         
  2651.         *)    return 2
  2652.             ;;
  2653.     esac
  2654.     
  2655.     return 2
  2656. }
  2657.  
  2658. # activation-phase command to check for the existance of
  2659. # a kernel module. It returns:
  2660. # 0 = module is already in the kernel
  2661. # 1 = module can be loaded with modprobe
  2662. # 2 = no info about this module in the kernel
  2663. check_kernel_module() {
  2664.     local mod="${1}"
  2665.     
  2666.     case ${mod} in
  2667.         ip_tables)
  2668.             test -f /proc/net/ip_tables_names && return 0
  2669.             check_kernel_config CONFIG_IP_NF_IPTABLES
  2670.             return $?
  2671.             ;;
  2672.         
  2673.         ip_conntrack)
  2674.             test -f /proc/net/ip_conntrack && return 0
  2675.             check_kernel_config CONFIG_IP_NF_CONNTRACK
  2676.             return $?
  2677.             ;;
  2678.             
  2679.         ip_conntrack_*)
  2680.             local mnam="CONFIG_IP_NF_`echo ${mod} | ${CUT_CMD} -d '_' -f 3- | ${TR_CMD} a-z A-Z`"
  2681.             check_kernel_config ${mnam}
  2682.             return $?
  2683.             ;;
  2684.             
  2685.         ip_nat_*)
  2686.             local mnam="CONFIG_IP_NF_NAT_`echo ${mod} | ${CUT_CMD} -d '_' -f 3- | ${TR_CMD} a-z A-Z`"
  2687.             check_kernel_config ${mnam}
  2688.             return $?
  2689.             ;;
  2690.             
  2691.         *)
  2692.             return 2
  2693.             ;;
  2694.     esac
  2695.     
  2696.     return 2
  2697. }
  2698.  
  2699. # activation-phase command to load a kernel module.
  2700. load_kernel_module() {
  2701.     local mod="${1}"
  2702.     
  2703.     if [ ! ${FIREHOL_LOAD_KERNEL_MODULES} -eq 0 ]
  2704.     then
  2705.         check_kernel_module ${mod}
  2706.         if [ $? -gt 0 ]
  2707.         then
  2708.             runcmd warn ${FIREHOL_LINEID} ${MODPROBE_CMD} ${mod} -q
  2709.         fi
  2710.     fi
  2711.     return 0
  2712. }
  2713.  
  2714. # Processing-phase command to tell FireHOL to find one or more
  2715. # kernel modules to load, during activation-phase.
  2716. require_kernel_module() {
  2717.     local new="${1}"
  2718.     
  2719.     local m=
  2720.     for m in ${FIREHOL_KERNEL_MODULES}
  2721.     do
  2722.         test "${m}" = "${new}" && return 0
  2723.     done
  2724.     
  2725.     FIREHOL_KERNEL_MODULES="${FIREHOL_KERNEL_MODULES} ${new}"
  2726.     
  2727.     return 0
  2728. }
  2729.  
  2730.  
  2731. # ------------------------------------------------------------------------------
  2732. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2733. # ------------------------------------------------------------------------------
  2734. #
  2735. # INTERNAL FUNCTIONS BELLOW THIS POINT - FireHOL internals
  2736. #
  2737. # ------------------------------------------------------------------------------
  2738. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  2739. # ------------------------------------------------------------------------------
  2740.  
  2741.  
  2742. set_work_function() {
  2743.     local show_explain=1
  2744.     test "$1" = "-ne" && shift && local show_explain=0
  2745.     
  2746.     work_function="$*"
  2747.     
  2748.     if [ ${FIREHOL_EXPLAIN} -eq 1 ]
  2749.     then
  2750.         test ${show_explain} -eq 1 && printf "\n# %s\n" "$*"
  2751.     elif [ ${FIREHOL_CONF_SHOW} -eq 1 ]
  2752.     then
  2753.         test ${show_explain} -eq 1 && printf "\n# INFO>>> %s\n" "$*" >>${FIREHOL_OUTPUT}
  2754.     fi
  2755. }
  2756.  
  2757.  
  2758. # ------------------------------------------------------------------------------
  2759. # Check the status of the current primary command.
  2760. # WHY:
  2761. # Some sanity check for the order of commands in the configuration file.
  2762. # Each function has a "require_work type command" in order to check that it is
  2763. # placed in a valid point. This means that if you place a "route" command in an
  2764. # interface section (and many other combinations) it will fail.
  2765.  
  2766. require_work() {
  2767.     local type="${1}"
  2768.     local cmd="${2}"
  2769.     
  2770.     case "${type}" in
  2771.         clear)
  2772.             test ! -z "${work_cmd}" && error "Previous work was not applied." && return 1
  2773.             ;;
  2774.         
  2775.         set)
  2776.             test -z "${work_cmd}" && error "The command used requires that a primary command is set." && return 1
  2777.             test ! "${work_cmd}" = "${cmd}" -a ! "${cmd}" = "any"  && error "Primary command is '${work_cmd}' but '${cmd}' is required." && return 1
  2778.             ;;
  2779.             
  2780.         *)
  2781.             error "Unknown work status '${type}'."
  2782.             return 1
  2783.             ;;
  2784.     esac
  2785.     
  2786.     return 0
  2787. }
  2788.  
  2789.  
  2790. # ------------------------------------------------------------------------------
  2791. # Finalizes the rules of the last primary command.
  2792. # WHY:
  2793. # At the end of an interface or router we need to add some code to apply its
  2794. # policy, accept all related packets, etc.
  2795. # Finalization occures automatically when a new primary command is executed and
  2796. # when the configuration file finishes.
  2797.  
  2798. close_cmd() {
  2799.     set_work_function -ne "Closing last open primary command (${work_cmd}/${work_name})"
  2800.     
  2801.     case "${work_cmd}" in
  2802.         interface)
  2803.             close_interface || return 1
  2804.             ;;
  2805.         
  2806.         router)
  2807.             close_router || return 1
  2808.             ;;
  2809.         
  2810.         '')
  2811.             ;;
  2812.         
  2813.         *)
  2814.             error "Unknown work '${work_cmd}'."
  2815.             return 1
  2816.             ;;
  2817.     esac
  2818.     
  2819.     # Reset the current status variables to empty/default
  2820.     work_counter=0
  2821.     work_cmd=
  2822.     work_realcmd=("(unset)")
  2823.     work_name=
  2824.     work_inface=
  2825.     work_outface=
  2826.     work_policy="${DEFAULT_INTERFACE_POLICY}"
  2827.     
  2828.     return 0
  2829. }
  2830.  
  2831. # ------------------------------------------------------------------------------
  2832. # close_interface
  2833. # WHY:
  2834. # Finalizes the rules for the last interface().
  2835.  
  2836. close_interface() {
  2837.     require_work set interface || return 1
  2838.     
  2839.     close_all_groups
  2840.     
  2841.     set_work_function "Finilizing interface '${work_name}'"
  2842.     
  2843.     case "${work_policy}" in
  2844.         return|RETURN)
  2845.             return 0
  2846.             ;;
  2847.             
  2848.         accept|ACCEPT)
  2849.             ;;
  2850.         
  2851.         *)
  2852.             local -a inlog=(loglimit "'IN-${work_name}'")
  2853.             local -a outlog=(loglimit "'OUT-${work_name}'")
  2854.             ;;
  2855.     esac
  2856.     
  2857.     # Accept all related traffic to the established connections
  2858.     rule chain "in_${work_name}" state RELATED action ACCEPT || return 1
  2859.     rule chain "out_${work_name}" state RELATED action ACCEPT || return 1
  2860.     
  2861.     rule chain "in_${work_name}" "${inlog[@]}" action ${work_policy} || return 1
  2862.     rule reverse chain "out_${work_name}" "${outlog[@]}" action ${work_policy} || return 1
  2863.     
  2864.     return 0
  2865. }
  2866.  
  2867.  
  2868. # ------------------------------------------------------------------------------
  2869. # close_router
  2870. # WHY:
  2871. # Finalizes the rules for the last router().
  2872.  
  2873. close_router() {    
  2874.     require_work set router || return 1
  2875.     
  2876.     close_all_groups
  2877.     
  2878.     set_work_function "Finilizing router '${work_name}'"
  2879.     
  2880.     # Accept all related traffic to the established connections
  2881.     rule chain "in_${work_name}" state RELATED action ACCEPT || return 1
  2882.     rule chain "out_${work_name}" state RELATED action ACCEPT || return 1
  2883.     
  2884.     return 0
  2885. }
  2886.  
  2887.  
  2888. # ------------------------------------------------------------------------------
  2889. # close_master
  2890. # WHY:
  2891. # Finalizes the rules for the whole firewall.
  2892. # It assummes there is not primary command open.
  2893.  
  2894. close_master() {
  2895.     set_work_function "Finilizing firewall policies"
  2896.     
  2897.     # Accept all related traffic to the established connections
  2898.     rule chain INPUT state RELATED action ACCEPT || return 1
  2899.     rule chain OUTPUT state RELATED action ACCEPT || return 1
  2900.     rule chain FORWARD state RELATED action ACCEPT || return 1
  2901.     
  2902.     rule chain INPUT loglimit "IN-unknown" action ${UNMATCHED_INPUT_POLICY} || return 1
  2903.     rule chain OUTPUT loglimit "OUT-unknown" action ${UNMATCHED_OUTPUT_POLICY} || return 1
  2904.     rule chain FORWARD loglimit "PASS-unknown" action ${UNMATCHED_ROUTER_POLICY} || return 1
  2905.     return 0
  2906. }
  2907.  
  2908.  
  2909. FIREHOL_GROUP_COUNTER=0
  2910. FIREHOL_GROUP_DEPTH=0
  2911. FIREHOL_GROUP_STACK=()
  2912. group() {
  2913.         work_realcmd_primary ${FUNCNAME} "$@"
  2914.     
  2915.     require_work set any || return 1
  2916.     
  2917.     local type="${1}"; shift
  2918.     
  2919.     case $type in
  2920.         with|start|begin)
  2921.             # increase the counter
  2922.             FIREHOL_GROUP_COUNTER=$[FIREHOL_GROUP_COUNTER + 1]
  2923.             
  2924.             set_work_function "Starting new group No ${FIREHOL_GROUP_COUNTER}, under '${work_name}'"
  2925.             
  2926.             # put the current name in the stack
  2927.             FIREHOL_GROUP_STACK[$FIREHOL_GROUP_DEPTH]=${work_name}
  2928.             FIREHOL_GROUP_DEPTH=$[FIREHOL_GROUP_DEPTH + 1]
  2929.             
  2930.             # name for the new chain
  2931.             mychain="group${FIREHOL_GROUP_COUNTER}"
  2932.             
  2933.             # create the new chain
  2934.             create_chain filter "in_${mychain}" "in_${work_name}" in "$@" || return 1
  2935.             create_chain filter "out_${mychain}" "out_${work_name}" out reverse "$@" || return 1
  2936.             
  2937.             # set a new name for new rules
  2938.             work_name=${mychain}
  2939.             ;;
  2940.         
  2941.         end|stop|close)
  2942.             if [ ${FIREHOL_GROUP_DEPTH} -eq 0 ]
  2943.             then
  2944.                 error "There is no group open to close."
  2945.                 return 1
  2946.             fi
  2947.             
  2948.             # pop one name from the stack
  2949.             FIREHOL_GROUP_DEPTH=$[FIREHOL_GROUP_DEPTH - 1]
  2950.             
  2951.             set_work_function "Closing group '${work_name}'. Now working under '${FIREHOL_GROUP_STACK[$FIREHOL_GROUP_DEPTH]}'"
  2952.             
  2953.             work_name=${FIREHOL_GROUP_STACK[$FIREHOL_GROUP_DEPTH]}
  2954.             ;;
  2955.         
  2956.         *)
  2957.             error "Statement 'group' requires the first argument to be one of with, start, begin, end, stop, close."
  2958.             return 1
  2959.             ;;
  2960.     esac
  2961.     
  2962.     return 0
  2963. }
  2964.  
  2965. close_all_groups() {
  2966.     while [ ${FIREHOL_GROUP_DEPTH} -gt 0 ]
  2967.     do
  2968.         group close || return 1
  2969.     done
  2970.     
  2971.     return 0
  2972. }
  2973.  
  2974.  
  2975.  
  2976. # ------------------------------------------------------------------------------
  2977. # rule - the heart of FireHOL - iptables commands generation
  2978. # WHY:
  2979. # This is the function that gives all the magic to FireHOL. Actually it is a
  2980. # wrapper for iptables, producing multiple iptables commands based on its
  2981. # arguments. The rest of FireHOL is simply a "driver" for this function.
  2982.  
  2983.  
  2984. # rule_action_param() is a function - part of rule() - to create the final iptables cmd
  2985. # taking into account the "action_param" parameter of the action.
  2986.  
  2987. # rule_action_param() should only be used within rule() - no other place
  2988.  
  2989. FIREHOL_ACCEPT_CHAIN_COUNT=0
  2990. rule_action_param() {
  2991.     local action="${1}"; shift
  2992.     local protocol="${1}"; shift
  2993.     local statenot="${1}"; shift
  2994.     local state="${1}"; shift
  2995.     local table="${1}"; shift
  2996.     local -a action_param=()
  2997.     
  2998.     # All arguments until the separator are the parameters of the action
  2999.     local count=0
  3000.     while [ ! -z "${1}" -a ! "A${1}" = "A--" ]
  3001.     do
  3002.         action_param[$count]="${1}"
  3003.         shift
  3004.         
  3005.         count=$[count + 1]
  3006.     done
  3007.     
  3008.     # If we don't have a seperator, generate an error
  3009.     local sep="${1}"; shift
  3010.     if [ ! "A${sep}" = "A--" ]
  3011.     then
  3012.         error "Internal Error, in parsing action_param parameters ($FUNCNAME '${action}' '${protocol}' '${statenot}' '${state}' '${table}' '${action_param[@]}' ${sep} '$@')."
  3013.         return 1
  3014.     fi
  3015.     
  3016.     # Do the rule
  3017.     case "${action}" in
  3018.         NONE)
  3019.             return 0
  3020.             ;;
  3021.             
  3022.         ACCEPT)
  3023.             # do we have any options for this accept?
  3024.             if [ ! -z "${action_param[0]}" ]
  3025.             then
  3026.                 # find the options we have
  3027.                 case "${action_param[0]}" in
  3028.                     "limit")
  3029.                         # limit NEW connections to the specified rate
  3030.                         local freq="${action_param[1]}"
  3031.                         local burst="${action_param[2]}"
  3032.                         local overflow="REJECT"
  3033.                         
  3034.                         # if we have a custom overflow action, parse it.
  3035.                         test "${action_param[3]}" = "overflow" && local overflow="`echo "${action_param[4]}" | tr "a-z" "A-Z"`"
  3036.                         
  3037.                         # unset the action_param, so that if this rule does not include NEW connections,
  3038.                         # we will not append anything to the generated iptables statements.
  3039.                         local -a action_param=()
  3040.                         
  3041.                         # find is this rule matches NEW connections
  3042.                         local has_new=`echo "${state}" | grep -i NEW`
  3043.                         local do_accept_limit=0
  3044.                         if [ -z "${statenot}" ]
  3045.                         then
  3046.                             test ! -z "${has_new}" && local do_accept_limit=1
  3047.                         else
  3048.                             test -z "${has_new}" && local do_accept_limit=1
  3049.                         fi
  3050.                         
  3051.                         # we have a match for NEW connections.
  3052.                         # redirect the traffic to a new chain, which will control
  3053.                         # the NEW connections while allowing all the other traffic
  3054.                         # to pass.
  3055.                         if [ "${do_accept_limit}" = "1" ]
  3056.                         then
  3057.                             local accept_limit_chain="`echo "ACCEPT ${freq} ${burst} ${overflow}" | tr " /." "___"`"
  3058.                             
  3059.                             # does the chain we need already exist?
  3060.                             if [ ! -f "${FIREHOL_CHAINS_DIR}/${accept_limit_chain}" ]
  3061.                             then
  3062.                                 # the chain does not exist. create it.
  3063.                                 iptables ${table} -N "${accept_limit_chain}"
  3064.                                 touch "${FIREHOL_CHAINS_DIR}/${accept_limit_chain}"
  3065.                                 
  3066.                                 # first, if the traffic is not a NEW connection, allow it.
  3067.                                 # doing this first will speed up normal traffic.
  3068.                                 iptables ${table} -A "${accept_limit_chain}" -m state ! --state NEW -j ACCEPT
  3069.                                 
  3070.                                 # accept NEW connections within the given limits.
  3071.                                 iptables ${table} -A "${accept_limit_chain}" -m limit --limit "${freq}" --limit-burst "${burst}" -j ACCEPT
  3072.                                 
  3073.                                 # log the overflow NEW connections reaching this step within the new chain
  3074.                                 local -a logopts_arg=()
  3075.                                 if [ "${FIREHOL_LOG_MODE}" = "ULOG" ]
  3076.                                 then
  3077.                                     local -a logopts_arg=("--ulog-prefix='OVERFLOW:'")
  3078.                                 else
  3079.                                     local -a logopts_arg=("--log-level" "${FIREHOL_LOG_LEVEL}" "--log-prefix='OVERFLOW:'")
  3080.                                 fi
  3081.                                 iptables ${table} -A "${accept_limit_chain}" -m limit --limit "${FIREHOL_LOG_FREQUENCY}" --limit-burst "${FIREHOL_LOG_BURST}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
  3082.                                 
  3083.                                 # if the overflow is to be rejected is tcp, reject it with TCP-RESET
  3084.                                 if [ "${overflow}" = "REJECT" ]
  3085.                                 then
  3086.                                     iptables ${table} -A "${accept_limit_chain}" -p tcp -j REJECT --reject-with tcp-reset
  3087.                                 fi
  3088.                                 
  3089.                                 # do the specified action on the overflow
  3090.                                 iptables ${table} -A "${accept_limit_chain}" -j ${overflow}
  3091.                             fi
  3092.                             
  3093.                             # send the rule to be generated to this chain
  3094.                             local action=${accept_limit_chain}
  3095.                         fi
  3096.                         ;;
  3097.                         
  3098.                     'knock')
  3099.                         # the name of the knock
  3100.                         local name="knock_${action_param[1]}"
  3101.                         
  3102.                         # unset the action_param, so that if this rule does not include NEW connections,
  3103.                         # we will not append anything to the generated iptables statements.
  3104.                         local -a action_param=()
  3105.                         
  3106.                         # does the knock chain exists?
  3107.                         if [ ! -f "${FIREHOL_CHAINS_DIR}/${name}" ]
  3108.                         then
  3109.                             # the chain does not exist. create it.
  3110.                             iptables ${table} -N "${name}"
  3111.                             touch "${FIREHOL_CHAINS_DIR}/${name}"
  3112.                             
  3113.                             iptables -A "${name}" -m state --state ESTABLISHED -j ACCEPT
  3114.                             
  3115.                             # knockd (http://www.zeroflux.org/knock/)
  3116.                             # will create more rules inside this chain to match NEW packets.
  3117.                         fi
  3118.                         
  3119.                         # send the rule to be generated to this knock chain
  3120.                         local action=${name}
  3121.                         ;;
  3122.                         
  3123.                     *)
  3124.                         error "Internal error. Cannot understand action ${action} with parameter '${action_param[0]}'."
  3125.                         return 1
  3126.                         ;;
  3127.                 esac
  3128.             fi
  3129.             ;;
  3130.             
  3131.         REJECT)
  3132.             if [ "${action_param[1]}" = "auto" ]
  3133.             then
  3134.                 if [ "${protocol}" = "tcp" -o "${protocol}" = "TCP" ]
  3135.                 then
  3136.                     action_param=("--reject-with" "tcp-reset")
  3137.                 else
  3138.                     action_param=()
  3139.                 fi
  3140.             fi
  3141.             ;;
  3142.     esac
  3143.     
  3144.     iptables "$@" -j "${action}" "${action_param[@]}"
  3145.     local ret=$?
  3146.     
  3147.     test $ret -gt 0 && failed=$[failed + 1]
  3148.     
  3149.     return $ret
  3150. }
  3151.  
  3152. rule() {
  3153.     local table=
  3154.     local chain=
  3155.     
  3156.     local inface=any
  3157.     local infacenot=
  3158.     
  3159.     local outface=any
  3160.     local outfacenot=
  3161.     
  3162.     local physin=any
  3163.     local physinnot=
  3164.     
  3165.     local physout=any
  3166.     local physoutnot=
  3167.     
  3168.     local mac=any
  3169.     local macnot=
  3170.     
  3171.     local src=any
  3172.     local srcnot=
  3173.     
  3174.     local dst=any
  3175.     local dstnot=
  3176.     
  3177.     local sport=any
  3178.     local sportnot=
  3179.     
  3180.     local dport=any
  3181.     local dportnot=
  3182.     
  3183.     local proto=any
  3184.     local protonot=
  3185.     
  3186.     local uid=any
  3187.     local uidnot=
  3188.     
  3189.     local gid=any
  3190.     local gidnot=
  3191.     
  3192.     local pid=any
  3193.     local pidnot=
  3194.     
  3195.     local sid=any
  3196.     local sidnot=
  3197.     
  3198.     local cmd=any
  3199.     local cmdnot=
  3200.     
  3201.     local mark=any
  3202.     local marknot=
  3203.     
  3204.     local dscp=any
  3205.     local dscptype=
  3206.     local despnot=
  3207.     
  3208.     local tos=any
  3209.     local tosnot=
  3210.     
  3211.     local log=
  3212.     local logtxt=
  3213.     local loglevel=
  3214.     
  3215.     local limit=
  3216.     local burst=
  3217.     
  3218.     local iplimit=
  3219.     local iplimit_mask=
  3220.     
  3221.     local action=
  3222.     
  3223.     local state=
  3224.     local statenot=
  3225.     
  3226.     local failed=0
  3227.     local reverse=0
  3228.     
  3229.     local swi=0
  3230.     local swo=0
  3231.     
  3232.     local custom=
  3233.     
  3234.     # if set to 1, all owner module options will be ignored
  3235.     local noowner=0
  3236.     
  3237.     # if set to 1, all mac options will be ignored
  3238.     local nomac=0
  3239.     
  3240.     # if set to 1, MIRROR will be converted to REJECT
  3241.     local nomirror=0
  3242.     
  3243.     # if set to 1, log and loglimit are ignored.
  3244.     local nolog=0
  3245.     
  3246.     # if set to 1, detection algorithm about overwritting optional rule
  3247.     # parameters will take place.
  3248.     local softwarnings=1
  3249.     
  3250.     # set it, in order to be local
  3251.     local -a action_param=()
  3252.     
  3253.     while [ ! -z "${1}" ]
  3254.     do
  3255.         case "${1}" in
  3256.             reverse|REVERSE)
  3257.                 reverse=1
  3258.                 shift
  3259.                 ;;
  3260.                 
  3261.             table|TABLE)
  3262.                 test ${softwarnings} -eq 1 -a ! -z "${table}" && softwarning "Overwritting param: ${1} '${chain}' becomes '${2}'"
  3263.                 table="-t ${2}"
  3264.                 shift 2
  3265.                 ;;
  3266.                 
  3267.             chain|CHAIN)
  3268.                 test ${softwarnings} -eq 1 -a ! -z "${chain}" && softwarning "Overwritting param: ${1} '${chain}' becomes '${2}'"
  3269.                 chain="${2}"
  3270.                 shift 2
  3271.                 ;;
  3272.                 
  3273.             inface|INFACE)
  3274.                 shift
  3275.                 if [ ${reverse} -eq 0 ]
  3276.                 then
  3277.                     infacenot=
  3278.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3279.                     then
  3280.                         shift
  3281.                         infacenot="!"
  3282.                     else
  3283.                         if [ $swi -eq 1 ]
  3284.                         then
  3285.                             work_inface="${1}"
  3286.                         fi
  3287.                     fi
  3288.                     test ${softwarnings} -eq 1 -a ! "${inface}" = "any" && softwarning "Overwritting param: inface '${inface}' becomes '${1}'"
  3289.                     inface="${1}"
  3290.                 else
  3291.                     outfacenot=
  3292.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3293.                     then
  3294.                         shift
  3295.                         outfacenot="!"
  3296.                     else
  3297.                         if [ ${swo} -eq 1 ]
  3298.                         then
  3299.                             work_outface="$1"
  3300.                         fi
  3301.                     fi
  3302.                     test ${softwarnings} -eq 1 -a ! "${outface}" = "any" && softwarning "Overwritting param: outface '${outface}' becomes '${1}'"
  3303.                     outface="${1}"
  3304.                 fi
  3305.                 shift
  3306.                 ;;
  3307.                 
  3308.             outface|OUTFACE)
  3309.                 shift
  3310.                 if [ ${reverse} -eq 0 ]
  3311.                 then
  3312.                     outfacenot=
  3313.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3314.                     then
  3315.                         shift
  3316.                         outfacenot="!"
  3317.                     else
  3318.                         if [ ${swo} -eq 1 ]
  3319.                         then
  3320.                             work_outface="${1}"
  3321.                         fi
  3322.                     fi
  3323.                     test ${softwarnings} -eq 1 -a ! "${outface}" = "any" && softwarning "Overwritting param: outface '${outface}' becomes '${1}'"
  3324.                     outface="${1}"
  3325.                 else
  3326.                     infacenot=
  3327.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3328.                     then
  3329.                         shift
  3330.                         infacenot="!"
  3331.                     else
  3332.                         if [ ${swi} -eq 1 ]
  3333.                         then
  3334.                             work_inface="${1}"
  3335.                         fi
  3336.                     fi
  3337.                     test ${softwarnings} -eq 1 -a ! "${inface}" = "any" && softwarning "Overwritting param: inface '${inface}' becomes '${1}'"
  3338.                     inface="${1}"
  3339.                 fi
  3340.                 shift
  3341.                 ;;
  3342.                 
  3343.             physin|PHYSIN)
  3344.                 shift
  3345.                 if [ ${reverse} -eq 0 ]
  3346.                 then
  3347.                     physinnot=
  3348.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3349.                     then
  3350.                         shift
  3351.                         physinnot="!"
  3352.                     fi
  3353.                     test ${softwarnings} -eq 1 -a ! "${physin}" = "any" && softwarning "Overwritting param: physin '${physin}' becomes '${1}'"
  3354.                     physin="${1}"
  3355.                 else
  3356.                     physoutnot=
  3357.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3358.                     then
  3359.                         shift
  3360.                         physoutnot="!"
  3361.                     fi
  3362.                     test ${softwarnings} -eq 1 -a ! "${physout}" = "any" && softwarning "Overwritting param: physout '${physout}' becomes '${1}'"
  3363.                     physout="${1}"
  3364.                 fi
  3365.                 shift
  3366.                 ;;
  3367.                 
  3368.             physout|PHYSOUT)
  3369.                 shift
  3370.                 if [ ${reverse} -eq 0 ]
  3371.                 then
  3372.                     physoutnot=
  3373.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3374.                     then
  3375.                         shift
  3376.                         physoutnot="!"
  3377.                     fi
  3378.                     test ${softwarnings} -eq 1 -a ! "${physout}" = "any" && softwarning "Overwritting param: physout '${physout}' becomes '${1}'"
  3379.                     physout="${1}"
  3380.                 else
  3381.                     physinnot=
  3382.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3383.                     then
  3384.                         shift
  3385.                         physinnot="!"
  3386.                     fi
  3387.                     test ${softwarnings} -eq 1 -a ! "${physin}" = "any" && softwarning "Overwritting param: physin '${physin}' becomes '${1}'"
  3388.                     physin="${1}"
  3389.                 fi
  3390.                 shift
  3391.                 ;;
  3392.                 
  3393.             mac|MAC)
  3394.                 shift
  3395.                 macnot=
  3396.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3397.                 then
  3398.                     shift
  3399.                     macnot="!"
  3400.                 fi
  3401.                 test ${softwarnings} -eq 1 -a ! "${mac}" = "any" && softwarning "Overwritting param: mac '${mac}' becomes '${1}'"
  3402.                 test ${nomac} -eq 0 && mac="${1}"
  3403.                 shift
  3404.                 ;;
  3405.                 
  3406.             src|SRC|source|SOURCE)
  3407.                 shift
  3408.                 if [ ${reverse} -eq 0 ]
  3409.                 then
  3410.                     srcnot=
  3411.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3412.                     then
  3413.                         shift
  3414.                         srcnot="!"
  3415.                     fi
  3416.                     test ${softwarnings} -eq 1 -a ! "${src}" = "any" && softwarning "Overwritting param: src '${src}' becomes '${1}'"
  3417.                     src="${1}"
  3418.                 else
  3419.                     dstnot=
  3420.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3421.                     then
  3422.                         shift
  3423.                         dstnot="!"
  3424.                     fi
  3425.                     test ${softwarnings} -eq 1 -a ! "${dst}" = "any" && softwarning "Overwritting param: dst '${dst}' becomes '${1}'"
  3426.                     dst="${1}"
  3427.                 fi
  3428.                 shift
  3429.                 ;;
  3430.                 
  3431.             dst|DST|destination|DESTINATION)
  3432.                 shift
  3433.                 if [ ${reverse} -eq 0 ]
  3434.                 then
  3435.                     dstnot=
  3436.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3437.                     then
  3438.                         shift
  3439.                         dstnot="!"
  3440.                     fi
  3441.                     test ${softwarnings} -eq 1 -a ! "${dst}" = "any" && softwarning "Overwritting param: dst '${dst}' becomes '${1}'"
  3442.                     dst="${1}"
  3443.                 else
  3444.                     srcnot=
  3445.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3446.                     then
  3447.                         shift
  3448.                         srcnot="!"
  3449.                     fi
  3450.                     test ${softwarnings} -eq 1 -a ! "${src}" = "any" && softwarning "Overwritting param: src '${src}' becomes '${1}'"
  3451.                     src="${1}"
  3452.                 fi
  3453.                 shift
  3454.                 ;;
  3455.                 
  3456.             sport|SPORT|sourceport|SOURCEPORT)
  3457.                 shift
  3458.                 if [ ${reverse} -eq 0 ]
  3459.                 then
  3460.                     sportnot=
  3461.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3462.                     then
  3463.                         shift
  3464.                         sportnot="!"
  3465.                     fi
  3466.                     test ${softwarnings} -eq 1 -a ! "${sport}" = "any" && softwarning "Overwritting param: sport '${sport}' becomes '${1}'"
  3467.                     sport="${1}"
  3468.                 else
  3469.                     dportnot=
  3470.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3471.                     then
  3472.                         shift
  3473.                         dportnot="!"
  3474.                     fi
  3475.                     test ${softwarnings} -eq 1 -a ! "${dport}" = "any" && softwarning "Overwritting param: dport '${dport}' becomes '${1}'"
  3476.                     dport="${1}"
  3477.                 fi
  3478.                 shift
  3479.                 ;;
  3480.                 
  3481.             dport|DPORT|destinationport|DESTINATIONPORT)
  3482.                 shift
  3483.                 if [ ${reverse} -eq 0 ]
  3484.                 then
  3485.                     dportnot=
  3486.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3487.                     then
  3488.                         shift
  3489.                         dportnot="!"
  3490.                     fi
  3491.                     test ${softwarnings} -eq 1 -a ! "${dport}" = "any" && softwarning "Overwritting param: dport '${dport}' becomes '${1}'"
  3492.                     dport="${1}"
  3493.                 else
  3494.                     sportnot=
  3495.                     if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3496.                     then
  3497.                         shift
  3498.                         sportnot="!"
  3499.                     fi
  3500.                     test ${softwarnings} -eq 1 -a ! "${sport}" = "any" && softwarning "Overwritting param: sport '${sport}' becomes '${1}'"
  3501.                     sport="${1}"
  3502.                 fi
  3503.                 shift
  3504.                 ;;
  3505.                 
  3506.             proto|PROTO|protocol|PROTOCOL)
  3507.                 shift
  3508.                 protonot=
  3509.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3510.                 then
  3511.                     shift
  3512.                     protonot="!"
  3513.                 fi
  3514.                 test ${softwarnings} -eq 1 -a ! "${proto}" = "any" && softwarning "Overwritting param: proto '${proto}' becomes '${1}'"
  3515.                 proto="${1}"
  3516.                 shift
  3517.                 ;;
  3518.                 
  3519.             mark|MARK)
  3520.                 shift
  3521.                 marknot=
  3522.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3523.                 then
  3524.                     shift
  3525.                     marknot="!"
  3526.                 fi
  3527.                 test ${softwarnings} -eq 1 -a ! "${mark}" = "any" && softwarning "Overwritting param: mark '${mark}' becomes '${1}'"
  3528.                 mark="${1}"
  3529.                 shift
  3530.                 ;;
  3531.                 
  3532.             tos|TOS)
  3533.                 shift
  3534.                 tosnot=
  3535.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3536.                 then
  3537.                     shift
  3538.                     tosnot="!"
  3539.                 fi
  3540.                 test ${softwarnings} -eq 1 -a ! "${tos}" = "any" && softwarning "Overwritting param: tos '${tos}' becomes '${1}'"
  3541.                 tos="${1}"
  3542.                 shift
  3543.                 ;;
  3544.                 
  3545.             dscp|DSCP)
  3546.                 shift
  3547.                 dscpnot=
  3548.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3549.                 then
  3550.                     shift
  3551.                     dscpnot="!"
  3552.                 fi
  3553.                 test ${softwarnings} -eq 1 -a ! "${dscp}" = "any" && softwarning "Overwritting param: dscp '${dscp}' becomes '${1}'"
  3554.                 dscp="${1}"
  3555.                 shift
  3556.                 
  3557.                 if [ "${dscp}" = "class" ]
  3558.                 then
  3559.                     dscptype="-class"
  3560.                     dscp="${1}"
  3561.                     shift
  3562.                 fi
  3563.                 ;;
  3564.                 
  3565.             action|ACTION)
  3566.                 test ${softwarnings} -eq 1 -a ! -z "${action}" && softwarning "Overwritting param: action '${action}' becomes '${2}'"
  3567.                 action="${2}"
  3568.                 shift 2
  3569.                 
  3570.                 local -a action_param=()
  3571.                 local action_is_chain=0
  3572.                 case "${action}" in
  3573.                     accept|ACCEPT)
  3574.                         action="ACCEPT"
  3575.                         
  3576.                         if [ "${1}" = "with" ]
  3577.                         then
  3578.                             shift
  3579.                             
  3580.                             case "${1}" in
  3581.                                 limit|LIMIT)
  3582.                                     local -a action_param=("limit" "${2}" "${3}")
  3583.                                     shift 3
  3584.                                     
  3585.                                     if [ "${1}" = "overflow" ]
  3586.                                     then
  3587.                                         action_param[3]="overflow"
  3588.                                         action_param[4]="${2}"
  3589.                                         shift 2
  3590.                                     fi
  3591.                                     ;;
  3592.                                 
  3593.                                 knock|KNOCK)
  3594.                                     local -a action_param=("knock" "${2}")
  3595.                                     shift 2
  3596.                                     ;;
  3597.                                 
  3598.                                 *)
  3599.                                     error "Cannot understand action's '${action}' directive '${1}'"
  3600.                                     return 1
  3601.                                     ;;
  3602.                             esac
  3603.                         fi
  3604.                         ;;
  3605.                         
  3606.                     deny|DENY|drop|DROP)
  3607.                         action="DROP"
  3608.                         ;;
  3609.                         
  3610.                     reject|REJECT)
  3611.                         action="REJECT"
  3612.                         if [ "${1}" = "with" ]
  3613.                         then
  3614.                             local -a action_param=("--reject-with" "${2}")
  3615.                             shift 2
  3616.                         else
  3617.                             local -a action_param=("--reject-with" "auto")
  3618.                         fi
  3619.                         ;;
  3620.                         
  3621.                     return|RETURN)
  3622.                         action="RETURN"
  3623.                         ;;
  3624.                         
  3625.                     mirror|MIRROR)
  3626.                         action="MIRROR"
  3627.                         test $nomirror -eq 1 && action="REJECT"
  3628.                         ;;
  3629.                         
  3630.                     none|NONE)
  3631.                         action="NONE"
  3632.                         ;;
  3633.                         
  3634.                     snat|SNAT)
  3635.                         action="SNAT"
  3636.                         if [ "${1}" = "to" ]
  3637.                         then
  3638.                             local -a action_param=()
  3639.                             local x=
  3640.                             for x in ${2}
  3641.                             do
  3642.                                 action_param=(${action_param[@]} "--to-source" "${x}")
  3643.                             done
  3644.                             shift 2
  3645.                         else
  3646.                             error "${action} requires a 'to' argument."
  3647.                             return 1
  3648.                         fi
  3649.                         if [ ! "A${table}" = "A-t nat" ]
  3650.                         then
  3651.                             error "${action} must on a the 'nat' table."
  3652.                             return 1
  3653.                         fi
  3654.                         ;;
  3655.                         
  3656.                     dnat|DNAT)
  3657.                         action="DNAT"
  3658.                         if [ "${1}" = "to" ]
  3659.                         then
  3660.                             local -a action_param=()
  3661.                             local x=
  3662.                             for x in ${2}
  3663.                             do
  3664.                                 action_param=(${action_param[@]} "--to-destination" "${x}")
  3665.                             done
  3666.                             shift 2
  3667.                         else
  3668.                             error "${action} requires a 'to' argument"
  3669.                             return 1
  3670.                         fi
  3671.                         if [ ! "A${table}" = "A-t nat" ]
  3672.                         then
  3673.                             error "${action} must on a the 'nat' table."
  3674.                             return 1
  3675.                         fi
  3676.                         ;;
  3677.                         
  3678.                     redirect|REDIRECT)
  3679.                         action="REDIRECT"
  3680.                         if [ "${1}" = "to-port" -o "${1}" = "to" ]
  3681.                         then
  3682.                             local -a action_param=("--to-ports" "${2}")
  3683.                             shift 2
  3684.                         else
  3685.                             error "${action} requires a 'to-port' or 'to' argument."
  3686.                             return 1
  3687.                         fi
  3688.                         if [ ! "A${table}" = "A-t nat" ]
  3689.                         then
  3690.                             error "${action} must on a the 'nat' table."
  3691.                             return 1
  3692.                         fi
  3693.                         ;;
  3694.                         
  3695.                     tos|TOS)
  3696.                         action="TOS"
  3697.                         if [ "${1}" = "to" ]
  3698.                         then
  3699.                             local -a action_param=("--set-tos" "${2}")
  3700.                             shift 2
  3701.                         else
  3702.                             error "${action} requires a 'to' argument"
  3703.                             return 1
  3704.                         fi
  3705.                         if [ ! "A${table}" = "A-t mangle" ]
  3706.                         then
  3707.                             error "${action} must on a the 'mangle' table."
  3708.                             return 1
  3709.                         fi
  3710.                         ;;
  3711.                         
  3712.                     mark|MARK)
  3713.                         action="MARK"
  3714.                         if [ "${1}" = "to" ]
  3715.                         then
  3716.                             local -a action_param=("--set-mark" "${2}")
  3717.                             shift 2
  3718.                         else
  3719.                             error "${action} requires a 'to' argument"
  3720.                             return 1
  3721.                         fi
  3722.                         if [ ! "A${table}" = "A-t mangle" ]
  3723.                         then
  3724.                             error "${action} must on a the 'mangle' table."
  3725.                             return 1
  3726.                         fi
  3727.                         ;;
  3728.                         
  3729.                     dscp|DSCP)
  3730.                         action="DSCP"
  3731.                         if [ "${1}" = "to" ]
  3732.                         then
  3733.                             if [ "${2}" = "class" ]
  3734.                             then
  3735.                                 local -a action_param=("--set-dscp-class" "${2}")
  3736.                                 shift
  3737.                             else
  3738.                                 local -a action_param=("--set-dscp" "${2}")
  3739.                             fi
  3740.                             shift 2
  3741.                         else
  3742.                             error "${action} requires a 'to' argument"
  3743.                             return 1
  3744.                         fi
  3745.                         if [ ! "A${table}" = "A-t mangle" ]
  3746.                         then
  3747.                             error "${action} must on a the 'mangle' table."
  3748.                             return 1
  3749.                         fi
  3750.                         ;;
  3751.                         
  3752.                     *)
  3753.                         chain_exists "${action}"
  3754.                         local action_is_chain=$?
  3755.                         ;;
  3756.                 esac
  3757.                 ;;
  3758.             
  3759.             state|STATE)
  3760.                 shift
  3761.                 statenot=
  3762.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3763.                 then
  3764.                     shift
  3765.                     statenot="!"
  3766.                 fi
  3767.                 test ${softwarnings} -eq 1 -a ! -z "${state}" && softwarning "Overwritting param: state '${state}' becomes '${1}'"
  3768.                 state="${1}"
  3769.                 shift
  3770.                 ;;
  3771.                 
  3772.             user|USER|uid|UID)
  3773.                 shift
  3774.                 uidnot=
  3775.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3776.                 then
  3777.                     shift
  3778.                     test ${noowner} -eq 0 && uidnot="!"
  3779.                 fi
  3780.                 test ${softwarnings} -eq 1 -a ! "${uid}" = "any" && softwarning "Overwritting param: uid '${uid}' becomes '${1}'"
  3781.                 test ${noowner} -eq 0 && uid="${1}"
  3782.                 shift
  3783.                 ;;
  3784.                 
  3785.             group|GROUP|gid|GID)
  3786.                 shift
  3787.                 gidnot=
  3788.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3789.                 then
  3790.                     shift
  3791.                     test ${noowner} -eq 0 && gidnot="!"
  3792.                 fi
  3793.                 test ${softwarnings} -eq 1 -a ! "${gid}" = "any" && softwarning "Overwritting param: gid '${gid}' becomes '${1}'"
  3794.                 test ${noowner} -eq 0 && gid="${1}"
  3795.                 shift
  3796.                 ;;
  3797.                 
  3798.             process|PROCESS|pid|PID)
  3799.                 shift
  3800.                 pidnot=
  3801.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3802.                 then
  3803.                     shift
  3804.                     test ${noowner} -eq 0 && pidnot="!"
  3805.                 fi
  3806.                 test ${softwarnings} -eq 1 -a ! "${pid}" = "any" && softwarning "Overwritting param: pid '${pid}' becomes '${1}'"
  3807.                 test ${noowner} -eq 0 && pid="${1}"
  3808.                 shift
  3809.                 ;;
  3810.                 
  3811.             session|SESSION|sid|SID)
  3812.                 shift
  3813.                 sidnot=
  3814.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3815.                 then
  3816.                     shift
  3817.                     test ${noowner} -eq 0 && sidnot="!"
  3818.                 fi
  3819.                 test ${softwarnings} -eq 1 -a ! "${sid}" = "any" && softwarning "Overwritting param: sid '${sid}' becomes '${1}'"
  3820.                 test ${noowner} -eq 0 && sid="${1}"
  3821.                 shift
  3822.                 ;;
  3823.                 
  3824.             command|COMMAND|cmd|CMD)
  3825.                 shift
  3826.                 cmdnot=
  3827.                 if [ "${1}" = "not" -o "${1}" = "NOT" ]
  3828.                 then
  3829.                     shift
  3830.                     test ${noowner} -eq 0 && cmdnot="!"
  3831.                 fi
  3832.                 test ${softwarnings} -eq 1 -a ! "${cmd}" = "any" && softwarning "Overwritting param: cmd '${cmd}' becomes '${1}'"
  3833.                 test ${noowner} -eq 0 && cmd="${1}"
  3834.                 shift
  3835.                 ;;
  3836.                 
  3837.             custom|CUSTOM)
  3838.                 test ${softwarnings} -eq 1 -a ! -z "${custom}" && softwarning "Overwritting param: custom '${custom}' becomes '${2}'"
  3839.                 custom="${2}"
  3840.                 shift 2
  3841.                 ;;
  3842.                 
  3843.             log|LOG)
  3844.                 if [ ${nolog} -eq 0 ]
  3845.                 then
  3846.                     test ${softwarnings} -eq 1 -a ! -z "${log}" && softwarning "Overwritting param: log '${log}/${logtxt}' becomes 'normal/${2}'"
  3847.                     log=normal
  3848.                     logtxt="${2}"
  3849.                 fi
  3850.                 shift 2
  3851.                 if [ "${1}" = "level" ]
  3852.                 then
  3853.                     loglevel="${2}"
  3854.                     shift 2
  3855.                 else
  3856.                     loglevel="${FIREHOL_LOG_LEVEL}"
  3857.                 fi
  3858.                 ;;
  3859.                 
  3860.             loglimit|LOGLIMIT)
  3861.                 if [ ${nolog} -eq 0 ]
  3862.                 then
  3863.                     test ${softwarnings} -eq 1 -a ! -z "${log}" && softwarning "Overwritting param: log '${log}/${logtxt}' becomes 'limit/${2}'"
  3864.                     log=limit
  3865.                     logtxt="${2}"
  3866.                 fi
  3867.                 shift 2
  3868.                 if [ "${1}" = "level" ]
  3869.                 then
  3870.                     loglevel="${2}"
  3871.                     shift 2
  3872.                 else
  3873.                     loglevel="${FIREHOL_LOG_LEVEL}"
  3874.                 fi
  3875.                 ;;
  3876.                 
  3877.             limit|LIMIT)
  3878.                 test ${softwarnings} -eq 1 -a ! -z "${limit}" && softwarning "Overwritting param: limit '${limit}' becomes '${2}'"
  3879.                 limit="${2}"
  3880.                 burst="${3}"
  3881.                 shift 3
  3882.                 ;;
  3883.                 
  3884.             iplimit|IPLIMIT)
  3885.                 test ${softwarnings} -eq 1 -a ! -z "${iplimit}" && softwarning "Overwritting param: iplimit '${iplimit}' becomes '${2}'"
  3886.                 iplimit="${2}"
  3887.                 iplimit_mask="${3}"
  3888.                 shift 3
  3889.                 ;;
  3890.                 
  3891.             in)    # this is incoming traffic - ignore packet ownership
  3892.                 local noowner=1
  3893.                 local nomirror=0
  3894.                 local nomac=0
  3895.                 shift
  3896.                 ;;
  3897.                 
  3898.             out)    # this is outgoing traffic - ignore packet ownership if not in an interface
  3899.                 if [ ! "${work_cmd}" = "interface" ]
  3900.                 then
  3901.                     local noowner=1
  3902.                 else
  3903.                     local nomirror=1
  3904.                 fi
  3905.                 local nomac=1
  3906.                 shift
  3907.                 ;;
  3908.                 
  3909.             nolog)
  3910.                 local nolog=1
  3911.                 shift
  3912.                 ;;
  3913.                 
  3914.             noowner)
  3915.                 local noowner=1
  3916.                 shift
  3917.                 ;;
  3918.                 
  3919.             softwarnings)
  3920.                 local softwarnings=1
  3921.                 shift
  3922.                 ;;
  3923.                 
  3924.             nosoftwarnings)
  3925.                 local softwarnings=0
  3926.                 shift
  3927.                 ;;
  3928.                 
  3929.             set_work_inface|SET_WORK_INFACE)
  3930.                 swi=1
  3931.                 shift
  3932.                 ;;
  3933.                 
  3934.             set_work_outface|SET_WORK_OUTFACE)
  3935.                 swo=1
  3936.                 shift
  3937.                 ;;
  3938.                 
  3939.             *)
  3940.                 error "Cannot understand directive '${1}'."
  3941.                 return 1
  3942.                 ;;
  3943.         esac
  3944.     done
  3945.     
  3946.     test -z "${table}" && table="-t filter"
  3947.     
  3948.     # If the user did not specified a rejection message,
  3949.     # we have to be smart and produce a tcp-reset if the protocol
  3950.     # is TCP and an ICMP port unreachable in all other cases.
  3951.     # The special case here is the protocol "any".
  3952.     # To accomplish the differentiation based on protocol we have
  3953.     # to change the protocol "any" to "tcp any"
  3954.     
  3955.     test "${action}" = "REJECT" -a "${action_param[1]}" = "auto" -a "${proto}" = "any" && proto="tcp any"
  3956.     
  3957.     
  3958.     # we cannot accept empty strings to a few parameters, since this
  3959.     # will prevent us from generating a rule (due to nested BASH loops).
  3960.     test -z "${inface}"    && error "Cannot accept an empty 'inface'."    && return 1
  3961.     test -z "${outface}"    && error "Cannot accept an empty 'outface'."    && return 1
  3962.     test -z "${physin}"    && error "Cannot accept an empty 'physin'."    && return 1
  3963.     test -z "${physout}"    && error "Cannot accept an empty 'physout'."    && return 1
  3964.     test -z "${mac}"    && error "Cannot accept an empty 'mac'."    && return 1
  3965.     test -z "${src}"    && error "Cannot accept an empty 'src'."    && return 1
  3966.     test -z "${dst}"    && error "Cannot accept an empty 'dst'."    && return 1
  3967.     test -z "${sport}"    && error "Cannot accept an empty 'sport'."    && return 1
  3968.     test -z "${dport}"    && error "Cannot accept an empty 'dport'."    && return 1
  3969.     test -z "${proto}"    && error "Cannot accept an empty 'proto'."    && return 1
  3970.     test -z "${uid}"    && error "Cannot accept an empty 'uid'."    && return 1
  3971.     test -z "${gid}"    && error "Cannot accept an empty 'gid'."    && return 1
  3972.     test -z "${pid}"    && error "Cannot accept an empty 'pid'."    && return 1
  3973.     test -z "${sid}"    && error "Cannot accept an empty 'sid'."    && return 1
  3974.     test -z "${cmd}"    && error "Cannot accept an empty 'cmd'."    && return 1
  3975.     
  3976.     
  3977.     # ----------------------------------------------------------------------------------
  3978.     # Do we have negative contitions?
  3979.     # If yes, we have to:
  3980.     #
  3981.     # case 1: If the action is a chain.
  3982.     #         Add to this chain positive RETURN statements matching all the negatives.
  3983.     #         The positive rules will be added bellow to the same chain and will be
  3984.     #         matched only if all RETURNs have not been matched.
  3985.     #
  3986.     # case 2: If the action is not a chain.
  3987.     #         Create a temporary chain, then add to this chain positive RETURN rules
  3988.     #         matching the negatives, and append at its end the final action (which is
  3989.     #         not a chain), then change the action of the positive rules to jump to
  3990.     #         this temporary chain.
  3991.     
  3992.     
  3993.     # ignore 'statenot' since it is negated in the positive rules
  3994.     if [ ! -z "${infacenot}${outfacenot}${physinnot}${physoutnot}${macnot}${srcnot}${dstnot}${sportnot}${dportnot}${protonot}${uidnot}${gidnot}${pidnot}${sidnot}${cmdnot}${marknot}${tosnot}${dscpnot}" ]
  3995.     then
  3996.         if [ ${action_is_chain} -eq 1 ]
  3997.         then
  3998.             # if the action is a chain name, then just add the negative
  3999.             # expressions to this chain. Nothing more.
  4000.             
  4001.             local negative_chain="${action}"
  4002.             local negative_action=
  4003.         else
  4004.             # if the action is a native iptables action, then create
  4005.             # an intermidiate chain to store the negative expression,
  4006.             # and change the action of the rule to point to this action.
  4007.             
  4008.             # In this case, bellow we add after all negatives, the original
  4009.             # action of the rule.
  4010.             
  4011.             local negative_chain="${chain}.${FIREHOL_DYNAMIC_CHAIN_COUNTER}"
  4012.             FIREHOL_DYNAMIC_CHAIN_COUNTER="$[FIREHOL_DYNAMIC_CHAIN_COUNTER + 1]"
  4013.             
  4014.             iptables ${table} -N "${negative_chain}"
  4015.             local negative_action="${action}"
  4016.             local action="${negative_chain}"
  4017.         fi
  4018.         
  4019.         
  4020.         if [ ! -z "${infacenot}" ]
  4021.         then
  4022.             local inf=
  4023.             for inf in ${inface}
  4024.             do
  4025.                 iptables ${table} -A "${negative_chain}" -i "${inf}" -j RETURN
  4026.             done
  4027.             infacenot=
  4028.             inface=any
  4029.         fi
  4030.     
  4031.         if [ ! -z "${outfacenot}" ]
  4032.         then
  4033.             local outf=
  4034.             for outf in ${outface}
  4035.             do
  4036.                 iptables ${table} -A "${negative_chain}" -o "${outf}" -j RETURN
  4037.             done
  4038.             outfacenot=
  4039.             outface=any
  4040.         fi
  4041.         
  4042.         if [ ! -z "${physinnot}" ]
  4043.         then
  4044.             local inph=
  4045.             for inph in ${physin}
  4046.             do
  4047.                 iptables ${table} -A "${negative_chain}" -m physdev --physdev-in "${inph}" -j RETURN
  4048.             done
  4049.             physinnot=
  4050.             physin=any
  4051.         fi
  4052.     
  4053.         if [ ! -z "${physoutnot}" ]
  4054.         then
  4055.             local outph=
  4056.             for outph in ${physout}
  4057.             do
  4058.                 iptables ${table} -A "${negative_chain}" -m physdev --physdev-out "${outph}" -j RETURN
  4059.             done
  4060.             physoutnot=
  4061.             physout=any
  4062.         fi
  4063.         
  4064.         if [ ! -z "${macnot}" ]
  4065.         then
  4066.             local m=
  4067.             for m in ${mac}
  4068.             do
  4069.                 iptables ${table} -A "${negative_chain}" -m mac --mac-source "${m}" -j RETURN
  4070.             done
  4071.             macnot=
  4072.             mac=any
  4073.         fi
  4074.         
  4075.         if [ ! -z "${srcnot}" ]
  4076.         then
  4077.             local s=
  4078.             for s in ${src}
  4079.             do
  4080.                 iptables ${table} -A "${negative_chain}" -s "${s}" -j RETURN
  4081.             done
  4082.             srcnot=
  4083.             src=any
  4084.         fi
  4085.         
  4086.         if [ ! -z "${dstnot}" ]
  4087.         then
  4088.             local d=
  4089.             for d in ${dst}
  4090.             do
  4091.                 iptables ${table} -A "${negative_chain}" -d "${d}" -j RETURN
  4092.             done
  4093.             dstnot=
  4094.             dst=any
  4095.         fi
  4096.         
  4097.         if [ ! -z "${protonot}" ]
  4098.         then
  4099.             if [ ! -z "${sportnot}" -o ! -z "${dportnot}" ]
  4100.             then
  4101.                 error "Cannot have negative protocol(s) and source/destination port(s)."
  4102.                 return 1
  4103.             fi
  4104.             
  4105.             local pr=
  4106.             for pr in ${proto}
  4107.             do
  4108.                 iptables ${table} -A "${negative_chain}" -p "${pr}" -j RETURN
  4109.             done
  4110.             protonot=
  4111.             proto=any
  4112.         fi
  4113.         
  4114.         if [ ! -z "${sportnot}" ]
  4115.         then
  4116.             if [ "${proto}" = "any" ]
  4117.             then
  4118.                 error "Cannot have negative source port specification without protocol."
  4119.                 return 1
  4120.             fi
  4121.             
  4122.             local sp=
  4123.             for sp in ${sport}
  4124.             do
  4125.                 local pr=
  4126.                 for pr in ${proto}
  4127.                 do
  4128.                     iptables ${table} -A "${negative_chain}" -p "${pr}" --sport "${sp}" -j RETURN
  4129.                 done
  4130.             done
  4131.             sportnot=
  4132.             sport=any
  4133.         fi
  4134.         
  4135.         if [ ! -z "${dportnot}" ]
  4136.         then
  4137.             if [ "${proto}" = "any" ]
  4138.             then
  4139.                 error "Cannot have negative destination port specification without protocol."
  4140.                 return 1
  4141.             fi
  4142.             
  4143.             local dp=
  4144.             for dp in ${dport}
  4145.             do
  4146.                 local pr=
  4147.                 for pr in ${proto}
  4148.                 do
  4149.                     iptables ${table} -A "${negative_chain}" -p "${pr}" --dport "${dp}" -j RETURN
  4150.                 done
  4151.             done
  4152.             dportnot=
  4153.             dport=any
  4154.         fi
  4155.         
  4156.         if [ ! -z "${uidnot}" ]
  4157.         then
  4158.             local tuid=
  4159.             for tuid in ${uid}
  4160.             do
  4161.                 iptables ${table} -A "${negative_chain}" -m owner --uid-owner "${tuid}" -j RETURN
  4162.             done
  4163.             uidnot=
  4164.             uid=any
  4165.         fi
  4166.         
  4167.         if [ ! -z "${gidnot}" ]
  4168.         then
  4169.             local tgid=
  4170.             for tgid in ${gid}
  4171.             do
  4172.                 iptables ${table} -A "${negative_chain}" -m owner --gid-owner "${tgid}" -j RETURN
  4173.             done
  4174.             gidnot=
  4175.             gid=any
  4176.         fi
  4177.         
  4178.         if [ ! -z "${pidnot}" ]
  4179.         then
  4180.             local tpid=
  4181.             for tpid in ${pid}
  4182.             do
  4183.                 iptables ${table} -A "${negative_chain}" -m owner --pid-owner "${tpid}" -j RETURN
  4184.             done
  4185.             pidnot=
  4186.             pid=any
  4187.         fi
  4188.         
  4189.         if [ ! -z "${sidnot}" ]
  4190.         then
  4191.             local tsid=
  4192.             for tsid in ${sid}
  4193.             do
  4194.                 iptables ${table} -A "${negative_chain}" -m owner --sid-owner "${tsid}" -j RETURN
  4195.             done
  4196.             sidnot=
  4197.             sid=any
  4198.         fi
  4199.         
  4200.         if [ ! -z "${cmdnot}" ]
  4201.         then
  4202.             local tcmd=
  4203.             for tcmd in ${cmd}
  4204.             do
  4205.                 iptables ${table} -A "${negative_chain}" -m owner --cmd-owner "${tcmd}" -j RETURN
  4206.             done
  4207.             cmdnot=
  4208.             cmd=any
  4209.         fi
  4210.         
  4211.         if [ ! -z "${marknot}" ]
  4212.         then
  4213.             local tmark=
  4214.             for tmark in ${mark}
  4215.             do
  4216.                 iptables ${table} -A "${negative_chain}" -m mark --mark "${tmark}" -j RETURN
  4217.             done
  4218.             marknot=
  4219.             mark=any
  4220.         fi
  4221.         
  4222.         if [ ! -z "${tosnot}" ]
  4223.         then
  4224.             local ttos=
  4225.             for ttos in ${tos}
  4226.             do
  4227.                 iptables ${table} -A "${negative_chain}" -m tos --tos "${ttos}" -j RETURN
  4228.             done
  4229.             tosnot=
  4230.             tos=any
  4231.         fi
  4232.         
  4233.         if [ ! -z "${dscpnot}" ]
  4234.         then
  4235.             local tdscp=
  4236.             for tdscp in ${dscp}
  4237.             do
  4238.                 iptables ${table} -A "${negative_chain}" -m dscp --dscp${dscptype} "${tdscp}" -j RETURN
  4239.             done
  4240.             dscp=any
  4241.             dscpnot=
  4242.         fi
  4243.         
  4244.         
  4245.         # in case this is temporary chain we created for the negative expression,
  4246.         # just make it have the final action of the rule.
  4247.         if [ ! -z "${negative_action}" ]
  4248.         then
  4249.             local pr=
  4250.             for pr in ${proto}
  4251.             do
  4252.                 local -a proto_arg=()
  4253.                 
  4254.                 case ${pr} in
  4255.                     any|ANY)
  4256.                         ;;
  4257.                     
  4258.                     *)
  4259.                         local -a proto_arg=("-p" "${pr}")
  4260.                         ;;
  4261.                 esac
  4262.                 
  4263.                 rule_action_param "${negative_action}" "${pr}" "" "" "${table}" "${action_param[@]}" -- ${table} -A "${negative_chain}" "${proto_arg[@]}"
  4264.                 local -a action_param=()
  4265.             done
  4266.         fi
  4267.     fi
  4268.     
  4269.     
  4270.     # ----------------------------------------------------------------------------------
  4271.     # Process the positive rules
  4272.     
  4273.     # uid
  4274.     local tuid=
  4275.     for tuid in ${uid}
  4276.     do
  4277.         local -a uid_arg=()
  4278.         local -a owner_arg=()
  4279.         
  4280.         case ${tuid} in
  4281.             any|ANY)
  4282.                 ;;
  4283.             
  4284.             *)
  4285.                 local -a owner_arg=("-m" "owner")
  4286.                 local -a uid_arg=("--uid-owner" "${tuid}")
  4287.                 ;;
  4288.         esac
  4289.     
  4290.     # gid
  4291.     local tgid=
  4292.     for tgid in ${gid}
  4293.     do
  4294.         local -a gid_arg=()
  4295.         
  4296.         case ${tgid} in
  4297.             any|ANY)
  4298.                 ;;
  4299.             
  4300.             *)
  4301.                 local -a owner_arg=("-m" "owner")
  4302.                 local -a gid_arg=("--gid-owner" "${tgid}")
  4303.                 ;;
  4304.         esac
  4305.     
  4306.     # pid
  4307.     local tpid=
  4308.     for tpid in ${pid}
  4309.     do
  4310.         local -a pid_arg=()
  4311.         
  4312.         case ${tpid} in
  4313.             any|ANY)
  4314.                 ;;
  4315.             
  4316.             *)
  4317.                 local -a owner_arg=("-m" "owner")
  4318.                 local -a pid_arg=("--pid-owner" "${tpid}")
  4319.                 ;;
  4320.         esac
  4321.     
  4322.     # sid
  4323.     local tsid=
  4324.     for tsid in ${sid}
  4325.     do
  4326.         local -a sid_arg=()
  4327.         
  4328.         case ${tsid} in
  4329.             any|ANY)
  4330.                 ;;
  4331.             
  4332.             *)
  4333.                 local -a owner_arg=("-m" "owner")
  4334.                 local -a sid_arg=("--sid-owner" "${tsid}")
  4335.                 ;;
  4336.         esac
  4337.     
  4338.     # cmd
  4339.     local tcmd=
  4340.     for tcmd in ${cmd}
  4341.     do
  4342.         local -a cmd_arg=()
  4343.         
  4344.         case ${tcmd} in
  4345.             any|ANY)
  4346.                 ;;
  4347.             
  4348.             *)
  4349.                 local -a owner_arg=("-m" "owner")
  4350.                 local -a cmd_arg=("--cmd-owner" "${tcmd}")
  4351.                 ;;
  4352.         esac
  4353.     
  4354.     # mark
  4355.     local tmark=
  4356.     for tmark in ${mark}
  4357.     do
  4358.         local -a mark_arg=()
  4359.         
  4360.         case ${tmark} in
  4361.             any|ANY)
  4362.                 ;;
  4363.             
  4364.             *)
  4365.                 local -a mark_arg=("-m" "mark" "--mark" "${tmark}")
  4366.                 ;;
  4367.         esac
  4368.     
  4369.     # tos
  4370.     local ttos=
  4371.     for ttos in ${tos}
  4372.     do
  4373.         local -a tos_arg=()
  4374.         
  4375.         case ${ttos} in
  4376.             any|ANY)
  4377.                 ;;
  4378.             
  4379.             *)
  4380.                 local -a tos_arg=("-m" "tos" "--tos" "${ttos}")
  4381.                 ;;
  4382.         esac
  4383.     
  4384.     # dscp
  4385.     local tdscp=
  4386.     for tdscp in ${dscp}
  4387.     do
  4388.         local -a dscp_arg=()
  4389.         
  4390.         case ${tdscp} in
  4391.             any|ANY)
  4392.                 ;;
  4393.             
  4394.             *)
  4395.                 local -a dscp_arg=("-m" "dscp" "--dscp${dscptype}" "${tdscp}")
  4396.                 ;;
  4397.         esac
  4398.     
  4399.     # proto
  4400.     local pr=
  4401.     for pr in ${proto}
  4402.     do
  4403.         local -a proto_arg=()
  4404.         
  4405.         case ${pr} in
  4406.             any|ANY)
  4407.                 ;;
  4408.             
  4409.             *)
  4410.                 local -a proto_arg=("-p" "${pr}")
  4411.                 ;;
  4412.         esac
  4413.     
  4414.     # inface
  4415.     local inf=
  4416.     for inf in ${inface}
  4417.     do
  4418.         local -a inf_arg=()
  4419.         case ${inf} in
  4420.             any|ANY)
  4421.                 ;;
  4422.             
  4423.             *)
  4424.                 local -a inf_arg=("-i" "${inf}")
  4425.                 ;;
  4426.         esac
  4427.     
  4428.     # outface
  4429.     local outf=
  4430.     for outf in ${outface}
  4431.     do
  4432.         local -a outf_arg=()
  4433.         case ${outf} in
  4434.             any|ANY)
  4435.                 ;;
  4436.             
  4437.             *)
  4438.                 local -a outf_arg=("-o" "${outf}")
  4439.                 ;;
  4440.         esac
  4441.     
  4442.     # physin
  4443.     local inph=
  4444.     for inph in ${physin}
  4445.     do
  4446.         local -a inph_arg=()
  4447.         case ${inph} in
  4448.             any|ANY)
  4449.                 ;;
  4450.             
  4451.             *)
  4452.                 local -a physdev_arg=("-m" "physdev")
  4453.                 local -a inph_arg=("--physdev-in" "${inph}")
  4454.                 ;;
  4455.         esac
  4456.     
  4457.     # physout
  4458.     local outph=
  4459.     for outph in ${physout}
  4460.     do
  4461.         local -a outph_arg=()
  4462.         case ${outph} in
  4463.             any|ANY)
  4464.                 ;;
  4465.             
  4466.             *)
  4467.                 local -a physdev_arg=("-m" "physdev")
  4468.                 local -a outph_arg=("--physdev-out" "${outph}")
  4469.                 ;;
  4470.         esac
  4471.     
  4472.     # sport
  4473.     local sp=
  4474.     for sp in ${sport}
  4475.     do
  4476.         local -a sp_arg=()
  4477.         case ${sp} in
  4478.             any|ANY)
  4479.                 ;;
  4480.             
  4481.             *)
  4482.                 local -a sp_arg=("--sport" "${sp}")
  4483.                 ;;
  4484.         esac
  4485.     
  4486.     # dport
  4487.     local dp=
  4488.     for dp in ${dport}
  4489.     do
  4490.         local -a dp_arg=()
  4491.         case ${dp} in
  4492.             any|ANY)
  4493.                 ;;
  4494.             
  4495.             *)
  4496.                 local -a dp_arg=("--dport" "${dp}")
  4497.                 ;;
  4498.         esac
  4499.     
  4500.     # mac
  4501.     local mc=
  4502.     for mc in ${mac}
  4503.     do
  4504.         local -a mc_arg=()
  4505.         case ${mc} in
  4506.             any|ANY)
  4507.                 ;;
  4508.             
  4509.             *)
  4510.                 local -a mc_arg=("-m" "mac" "--mac-source" "${mc}")
  4511.                 ;;
  4512.         esac
  4513.     
  4514.     # src
  4515.     local s=
  4516.     for s in ${src}
  4517.     do
  4518.         local -a s_arg=()
  4519.         case ${s} in
  4520.             any|ANY)
  4521.                 ;;
  4522.             
  4523.             *)
  4524.                 local -a s_arg=("-s" "${s}")
  4525.                 ;;
  4526.         esac
  4527.     
  4528.     # dst
  4529.     local d=
  4530.     for d in ${dst}
  4531.     do
  4532.         local -a d_arg=()
  4533.         case ${d} in
  4534.             any|ANY)
  4535.                 ;;
  4536.             
  4537.             *)
  4538.                 local -a d_arg=("-d" "${d}")
  4539.                 ;;
  4540.         esac
  4541.     
  4542.     # state
  4543.     local -a state_arg=()
  4544.     if [ ! -z "${state}" ]
  4545.     then
  4546.         local -a state_arg=("-m" "state" "${statenot}" "--state" "${state}")
  4547.     fi
  4548.     
  4549.     # limit
  4550.     local -a limit_arg=()
  4551.     if [ ! -z "${limit}" ]
  4552.     then
  4553.         local -a limit_arg=("-m" "limit" "--limit" "${limit}" "--limit-burst" "${burst}")
  4554.     fi
  4555.     
  4556.     # iplimit
  4557.     local -a iplimit_arg=()
  4558.     if [ ! -z "${iplimit}" ]
  4559.     then
  4560.         local -a iplimit_arg=("-m" "iplimit" "--iplimit-above" "${iplimit}" "--iplimit-mask" "${iplimit_mask}")
  4561.     fi
  4562.     
  4563.     # build the command
  4564.     declare -a basecmd=("${inf_arg[@]}" "${outf_arg[@]}" "${physdev_arg[@]}" "${inph_arg[@]}" "${outph_arg[@]}" "${limit_arg[@]}" "${iplimit_arg[@]}" "${proto_arg[@]}" "${s_arg[@]}" "${sp_arg[@]}" "${d_arg[@]}" "${dp_arg[@]}" "${owner_arg[@]}" "${uid_arg[@]}" "${gid_arg[@]}" "${pid_arg[@]}" "${sid_arg[@]}" "${cmd_arg[@]}" "${state_arg[@]}" "${mc_arg[@]}" "${mark_arg[@]}" "${tos_arg[@]}" "${dscp_arg[@]}")
  4565.     
  4566.     # log mode selection
  4567.     local -a logopts_arg=()
  4568.     if [ "${FIREHOL_LOG_MODE}" = "ULOG" ]
  4569.     then
  4570.         local -a logopts_arg=("--ulog-prefix='${logtxt}:'")
  4571.     else
  4572.         local -a logopts_arg=("--log-level" "${loglevel}" "--log-prefix='${logtxt}:'")
  4573.     fi
  4574.     
  4575.     # log / loglimit
  4576.     case "${log}" in
  4577.         '')
  4578.             ;;
  4579.         
  4580.         limit)
  4581.             iptables ${table} -A "${chain}" "${basecmd[@]}" ${custom} -m limit --limit "${FIREHOL_LOG_FREQUENCY}" --limit-burst "${FIREHOL_LOG_BURST}" -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
  4582.             ;;
  4583.             
  4584.         normal)
  4585.             iptables ${table} -A "${chain}" "${basecmd[@]}" ${custom}  -j ${FIREHOL_LOG_MODE} ${FIREHOL_LOG_OPTIONS} "${logopts_arg[@]}"
  4586.             ;;
  4587.             
  4588.         *)
  4589.             error "Unknown log value '${log}'."
  4590.             ;;
  4591.     esac
  4592.     
  4593.     # do it!
  4594.     rule_action_param "${action}" "${pr}" "${statenot}" "${state}" "${table}" "${action_param[@]}" -- ${table} -A "${chain}" "${basecmd[@]}" ${custom}
  4595.     
  4596.     done # dst
  4597.     done # src
  4598.     done # mac
  4599.     done # dport
  4600.     done # sport
  4601.     done # physout
  4602.     done # physin
  4603.     done # outface
  4604.     done # inface
  4605.     done # proto
  4606.     done # dscp
  4607.     done # tos
  4608.     done # mark
  4609.     done # cmd
  4610.     done # sid
  4611.     done # pid
  4612.     done # gid
  4613.     done # uid
  4614.     
  4615.     test ${failed} -gt 0 && error "There are ${failed} failed commands." && return 1
  4616.     return 0
  4617. }
  4618.  
  4619.  
  4620. softwarning() {
  4621.     echo >&2
  4622.     echo >&2 "--------------------------------------------------------------------------------"
  4623.     echo >&2 "WARNING"
  4624.     echo >&2 "WHAT   : ${work_function}"
  4625.     echo >&2 "WHY    :" "$@"
  4626.     printf >&2 "COMMAND: "; printf >&2 "%q " "${work_realcmd[@]}"; echo >&2
  4627.     echo >&2 "SOURCE : line ${FIREHOL_LINEID} of ${FIREHOL_CONFIG}"
  4628.     echo >&2
  4629.     
  4630.     return 0
  4631. }
  4632.  
  4633. # ------------------------------------------------------------------------------
  4634. # error - error reporting while still parsing the configuration file
  4635. # WHY:
  4636. # This is the error handler that presents to the user detected errors during
  4637. # processing FireHOL's configuration file.
  4638. # This command is directly called by other functions of FireHOL.
  4639.  
  4640. error() {
  4641.     work_error=$[work_error + 1]
  4642.     echo >&2
  4643.     echo >&2 "--------------------------------------------------------------------------------"
  4644.     echo >&2 "ERROR #: ${work_error}"
  4645.     echo >&2 "WHAT   : ${work_function}"
  4646.     echo >&2 "WHY    :" "$@"
  4647.     printf >&2 "COMMAND: "; printf >&2 "%q " "${work_realcmd[@]}"; echo >&2
  4648.     echo >&2 "SOURCE : line ${FIREHOL_LINEID} of ${FIREHOL_CONFIG}"
  4649.     echo >&2
  4650.     
  4651.     return 0
  4652. }
  4653.  
  4654.  
  4655. # ------------------------------------------------------------------------------
  4656. # runtime_error - postprocessing evaluation of commands run
  4657. # WHY:
  4658. # The generated iptables commands must be checked for errors in case they fail.
  4659. # This command is executed after every postprocessing command to find out
  4660. # if it has been successfull or failed.
  4661.  
  4662. runtime_error() {
  4663.     local type="ERROR"
  4664.     local id=
  4665.     
  4666.     case "${1}" in
  4667.         error)
  4668.             local type="ERROR  "
  4669.             work_final_status=$[work_final_status + 1]
  4670.             local id="# ${work_final_status}."
  4671.             ;;
  4672.             
  4673.         warn)
  4674.             local type="WARNING"
  4675.             local id="This might or might not affect the operation of your firewall."
  4676.             ;;
  4677.         
  4678.         *)
  4679.             work_final_status=$[work_final_status + 1]
  4680.             local id="# ${work_final_status}."
  4681.             
  4682.             echo >&2
  4683.             echo >&2
  4684.             echo >&2 "*** unsupported final status type '${1}'. Assuming it is 'ERROR'"
  4685.             echo >&2
  4686.             echo >&2
  4687.             ;;
  4688.     esac
  4689.     shift
  4690.     
  4691.     local ret="${1}"; shift
  4692.     local line="${1}"; shift
  4693.     
  4694.     echo >&2
  4695.     echo >&2
  4696.     echo >&2 "--------------------------------------------------------------------------------"
  4697.     echo >&2 "${type} : ${id}"
  4698.     echo >&2 "WHAT    : A runtime command failed to execute (returned error ${ret})."
  4699.     echo >&2 "SOURCE  : line ${line} of ${FIREHOL_CONFIG}"
  4700.     printf >&2 "COMMAND : "
  4701.     printf >&2 "%q " "$@"
  4702.     printf >&2 "\n"
  4703.     echo >&2 "OUTPUT  : "
  4704.     echo >&2
  4705.     ${CAT_CMD} ${FIREHOL_OUTPUT}.log
  4706.     echo >&2
  4707.     
  4708.     return 0
  4709. }
  4710.  
  4711.  
  4712. # ------------------------------------------------------------------------------
  4713. # chain_exists - find if chain name has already being specified
  4714. # WHY:
  4715. # We have to make sure each service gets its own chain.
  4716. # Although FireHOL chain naming makes chains with unique names, this is just
  4717. # an extra sanity check.
  4718.  
  4719. chain_exists() {
  4720.     local chain="${1}"
  4721.     
  4722.     test -f "${FIREHOL_CHAINS_DIR}/${chain}" && return 1
  4723.     return 0
  4724. }
  4725.  
  4726.  
  4727. # ------------------------------------------------------------------------------
  4728. # create_chain - create a chain and link it to the firewall
  4729. # WHY:
  4730. # When a chain is created it must somehow to be linked to the rest of the
  4731. # firewall apropriately. This function first creates the chain and then
  4732. # it links it to its final position within the generated firewall.
  4733.  
  4734. create_chain() {
  4735.     local table="${1}"
  4736.     local newchain="${2}"
  4737.     local oldchain="${3}"
  4738.     shift 3
  4739.     
  4740.     set_work_function "Creating chain '${newchain}' under '${oldchain}' in table '${table}'"
  4741.     
  4742.     chain_exists "${newchain}"
  4743.     test $? -eq 1 && error "Chain '${newchain}' already exists." && return 1
  4744.     
  4745.     iptables -t ${table} -N "${newchain}" || return 1
  4746.     ${TOUCH_CMD} "${FIREHOL_CHAINS_DIR}/${newchain}"
  4747.     
  4748.     rule table ${table} chain "${oldchain}" action "${newchain}" "$@" || return 1
  4749.     
  4750.     return 0
  4751. }
  4752.  
  4753.  
  4754. # ------------------------------------------------------------------------------
  4755. # smart_function - find the valid service definition for a service
  4756. # WHY:
  4757. # FireHOL supports simple and complex services. This function first tries to
  4758. # detect if there are the proper variables set for a simple service, and if
  4759. # they do not exist, it then tries to find the complex function definition for
  4760. # the service.
  4761. #
  4762. # Additionally, it creates a chain for the subcommand.
  4763.  
  4764. smart_function() {
  4765.     local type="${1}"    # The current subcommand: server/client/route
  4766.     local services="${2}"    # The services to implement
  4767.     shift 2
  4768.     
  4769.     local service=
  4770.     for service in $services
  4771.     do
  4772.         local servname="${service}"
  4773.         test "${service}" = "custom" && local servname="${1}"
  4774.         
  4775.         set_work_function "Preparing for service '${service}' of type '${type}' under interface '${work_name}'"
  4776.         
  4777.         # Increase the command counter, to make all chains within a primary
  4778.         # command, unique.
  4779.         work_counter=$[work_counter + 1]
  4780.         
  4781.         local suffix="u${work_counter}"
  4782.         case "${type}" in
  4783.             client)
  4784.                 suffix="c${work_counter}"
  4785.                 ;;
  4786.             
  4787.             server)
  4788.                 suffix="s${work_counter}"
  4789.                 ;;
  4790.             
  4791.             route)
  4792.                 suffix="r${work_counter}"
  4793.                 ;;
  4794.             
  4795.             *)    error "Cannot understand type '${type}'."
  4796.                 return 1
  4797.                 ;;
  4798.         esac
  4799.         
  4800.         local mychain="${work_name}_${servname}_${suffix}"
  4801.         
  4802.         create_chain filter "in_${mychain}" "in_${work_name}" || return 1
  4803.         create_chain filter "out_${mychain}" "out_${work_name}" || return 1
  4804.         
  4805.         # Try the simple services first
  4806.         simple_service "${mychain}" "${type}" "${service}" "$@"
  4807.         local ret=$?
  4808.         
  4809.         # simple service completed succesfully.
  4810.         test $ret -eq 0 && continue
  4811.         
  4812.         # simple service exists but failed.
  4813.         if [ $ret -ne 127 ]
  4814.         then
  4815.             error "Simple service '${service}' returned an error ($ret)."
  4816.             return 1
  4817.         fi
  4818.         
  4819.         
  4820.         # Try the custom services
  4821.         local fn="rules_${service}"
  4822.         
  4823.         set_work_function "Running complex rules function ${fn}() for ${type} '${service}'"
  4824.         
  4825.         "${fn}" "${mychain}" "${type}" "$@"
  4826.         local ret=$?
  4827.         test $ret -eq 0 && continue
  4828.         
  4829.         if [ $ret -eq 127 ]
  4830.         then
  4831.             error "There is no service '${service}' defined."
  4832.         else
  4833.             error "Complex service '${service}' returned an error ($ret)."
  4834.         fi
  4835.         return 1
  4836.     done
  4837.     
  4838.     return 0
  4839. }
  4840.  
  4841. # ------------------------------------------------------------------------------
  4842. # simple_service - convert a service definition to an inline service definition
  4843. # WHY:
  4844. # When a simple service is detected, there must be someone to call
  4845. # rules_custom() with the appropriate service definition parameters.
  4846.  
  4847. simple_service() {
  4848.     local mychain="${1}"; shift
  4849.     local type="${1}"; shift
  4850.     local server="${1}"; shift
  4851.     
  4852.     local server_varname="server_${server}_ports"
  4853.     eval local server_ports="\$${server_varname}"
  4854.     
  4855.     local client_varname="client_${server}_ports"
  4856.     eval local client_ports="\$${client_varname}"
  4857.     
  4858.     test -z "${server_ports}" -o -z "${client_ports}" && return 127
  4859.     
  4860.     local x=
  4861.     local varname="require_${server}_modules"
  4862.     eval local value="\$${varname}"
  4863.     for x in ${value}
  4864.     do
  4865.         require_kernel_module $x || return 1
  4866.     done
  4867.     
  4868.     if [ ${FIREHOL_NAT} -eq 1 ]
  4869.     then
  4870.         local varname="require_${server}_nat_modules"
  4871.         eval local value="\$${varname}"
  4872.         for x in ${value}
  4873.         do
  4874.             require_kernel_module $x || return 1
  4875.         done
  4876.     fi
  4877.     
  4878.     set_work_function "Running simple rules for  ${type} '${service}'"
  4879.     
  4880.     rules_custom "${mychain}" "${type}" "${server}" "${server_ports}" "${client_ports}" "$@"
  4881.     return $?
  4882. }
  4883.  
  4884. show_work_realcmd() {
  4885.     test ${FIREHOL_EXPLAIN} -eq 1 && return 0
  4886.     
  4887.     (
  4888.         printf "\n\n"
  4889.         printf "# === CONFIGURATION STATEMENT =================================================\n"
  4890.         printf "# CONF:%3s>>>    " ${FIREHOL_LINEID}
  4891.         
  4892.         case $1 in
  4893.             2)    printf "    "
  4894.                 ;;
  4895.             *)    ;;
  4896.         esac
  4897.         
  4898.         printf "%q " "${work_realcmd[@]}"
  4899.         printf "\n\n"
  4900.     ) >>${FIREHOL_OUTPUT}
  4901. }
  4902.  
  4903. work_realcmd_primary() {
  4904.     work_realcmd=("$@")
  4905.     test ${FIREHOL_CONF_SHOW} -eq 1 && show_work_realcmd 1
  4906. }
  4907.  
  4908. work_realcmd_secondary() {
  4909.     work_realcmd=("$@")
  4910.     test ${FIREHOL_CONF_SHOW} -eq 1 && show_work_realcmd 2
  4911. }
  4912.  
  4913. work_realcmd_helper() {    
  4914.     work_realcmd=("$@")
  4915.     test ${FIREHOL_CONF_SHOW} -eq 1 && show_work_realcmd 3
  4916. }
  4917.  
  4918.  
  4919.  
  4920. # ------------------------------------------------------------------------------
  4921. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  4922. # ------------------------------------------------------------------------------
  4923. #
  4924. # START UP SCRIPT PROCESSING
  4925. #
  4926. # ------------------------------------------------------------------------------
  4927. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  4928. # ------------------------------------------------------------------------------
  4929.  
  4930. # ------------------------------------------------------------------------------
  4931. # On non RedHat machines we need success() and failure()
  4932. success() {
  4933.     printf " OK"
  4934. }
  4935. failure() {
  4936.     echo " FAILED"
  4937. }
  4938.  
  4939. # ------------------------------------------------------------------------------
  4940. # A small part bellow is copied from /etc/init.d/iptables
  4941.  
  4942. # On RedHat systems this will define success() and failure()
  4943. test -f /etc/init.d/functions && . /etc/init.d/functions
  4944.  
  4945. if [ -z "${IPTABLES_CMD}" -o ! -x "${IPTABLES_CMD}" ]; then
  4946.     echo >&2 "Cannot find an executables iptables command."
  4947.     exit 0
  4948. fi
  4949.  
  4950. KERNELMAJ=`${UNAME_CMD} -r | ${SED_CMD}                   -e 's,\..*,,'`
  4951. KERNELMIN=`${UNAME_CMD} -r | ${SED_CMD} -e 's,[^\.]*\.,,' -e 's,\..*,,'`
  4952.  
  4953. if [ "$KERNELMAJ" -lt 2 ] ; then
  4954.     echo >&2 "FireHOL requires a kernel version higher than 2.3."
  4955.     exit 0
  4956. fi
  4957. if [ "$KERNELMAJ" -eq 2 -a "$KERNELMIN" -lt 3 ] ; then
  4958.     echo >&2 "FireHOL requires a kernel version higher than 2.3."
  4959.     exit 0
  4960. fi
  4961.  
  4962. if  ${LSMOD_CMD} 2>/dev/null | ${GREP_CMD} -q ipchains ; then
  4963.     # Don't do both
  4964.     echo >&2 "ipchains is loaded in the kernel. Please remove ipchains to run iptables."
  4965.     exit 0
  4966. fi
  4967.  
  4968.  
  4969. # ------------------------------------------------------------------------------
  4970. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  4971. # ------------------------------------------------------------------------------
  4972. #
  4973. # COMMAND LINE ARGUMENTS PROCESSING
  4974. #
  4975. # ------------------------------------------------------------------------------
  4976. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  4977. # ------------------------------------------------------------------------------
  4978.  
  4979. me="${0}"
  4980. arg="${1}"
  4981. shift
  4982.  
  4983. case "${arg}" in
  4984.     explain)
  4985.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  4986.         FIREHOL_EXPLAIN=1
  4987.         ;;
  4988.     
  4989.     helpme|wizard)
  4990.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  4991.         FIREHOL_WIZARD=1
  4992.         ;;
  4993.     
  4994.     try)
  4995.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  4996.         FIREHOL_TRY=1
  4997.         ;;
  4998.     
  4999.     start)
  5000.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5001.         FIREHOL_TRY=0
  5002.         ;;
  5003.     
  5004.     stop)
  5005.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5006.         
  5007.         test -f /var/lock/subsys/firehol && ${RM_CMD} -f /var/lock/subsys/firehol
  5008.         test -f /var/lock/subsys/iptables && ${RM_CMD} -f /var/lock/subsys/iptables
  5009.         
  5010.         echo -n $"FireHOL: Clearing Firewall:"
  5011.         load_kernel_module ip_tables
  5012.         tables=`${CAT_CMD} /proc/net/ip_tables_names`
  5013.         for t in ${tables}
  5014.         do
  5015.             ${IPTABLES_CMD} -t "${t}" -F
  5016.             ${IPTABLES_CMD} -t "${t}" -X
  5017.             ${IPTABLES_CMD} -t "${t}" -Z
  5018.             
  5019.             # Find all default chains in this table.
  5020.             chains=`${IPTABLES_CMD} -t "${t}" -nL | ${GREP_CMD} "^Chain " | ${CUT_CMD} -d ' ' -f 2`
  5021.             for c in ${chains}
  5022.             do
  5023.                 ${IPTABLES_CMD} -t "${t}" -P "${c}" ACCEPT
  5024.             done
  5025.         done
  5026.         success $"FireHOL: Clearing Firewall:"
  5027.         echo
  5028.         
  5029.         exit 0
  5030.         ;;
  5031.     
  5032.     restart|force-reload)
  5033.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5034.         FIREHOL_TRY=0
  5035.         ;;
  5036.     
  5037.     condrestart)
  5038.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5039.         FIREHOL_TRY=0
  5040.         if [ -f /var/lock/subsys/firehol ]
  5041.         then
  5042.             exit 0
  5043.         fi
  5044.         ;;
  5045.     
  5046.     status)
  5047.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5048.         (
  5049.             echo 
  5050.             echo "--- MANGLE ---------------------------------------------------------------------"
  5051.             echo 
  5052.             ${IPTABLES_CMD} -t mangle -nxvL
  5053.             
  5054.             echo 
  5055.             echo 
  5056.             echo "--- NAT ------------------------------------------------------------------------"
  5057.             echo 
  5058.             ${IPTABLES_CMD} -t nat -nxvL
  5059.             
  5060.             echo 
  5061.             echo 
  5062.             echo "--- FILTER ---------------------------------------------------------------------"
  5063.             echo 
  5064.             ${IPTABLES_CMD} -nxvL
  5065.         ) | ${LESS_CMD}
  5066.         exit $?
  5067.         ;;
  5068.     
  5069.     panic)
  5070.         ssh_src=
  5071.         ssh_sport="0:65535"
  5072.         ssh_dport="0:65535"
  5073.         if [ ! -z "${SSH_CLIENT}" ]
  5074.         then
  5075.             set -- ${SSH_CLIENT}
  5076.             ssh_src="${1}"
  5077.             ssh_sport="${2}"
  5078.             ssh_dport="${3}"
  5079.         elif [ ! -z "${1}" ]
  5080.         then
  5081.             ssh_src="${1}"
  5082.         fi
  5083.         
  5084.         echo -n $"FireHOL: Blocking all communications:"
  5085.         load_kernel_module ip_tables
  5086.         tables=`${CAT_CMD} /proc/net/ip_tables_names`
  5087.         for t in ${tables}
  5088.         do
  5089.             ${IPTABLES_CMD} -t "${t}" -F
  5090.             ${IPTABLES_CMD} -t "${t}" -X
  5091.             ${IPTABLES_CMD} -t "${t}" -Z
  5092.             
  5093.             # Find all default chains in this table.
  5094.             chains=`${IPTABLES_CMD} -t "${t}" -nL | ${GREP_CMD} "^Chain " | ${CUT_CMD} -d ' ' -f 2`
  5095.             for c in ${chains}
  5096.             do
  5097.                 ${IPTABLES_CMD} -t "${t}" -P "${c}" ACCEPT
  5098.                 
  5099.                 if [ ! -z "${ssh_src}" ]
  5100.                 then
  5101.                     ${IPTABLES_CMD} -t "${t}" -A "${c}" -p tcp -s "${ssh_src}" --sport "${ssh_sport}" --dport "${ssh_dport}" -m state --state ESTABLISHED -j ACCEPT
  5102.                     ${IPTABLES_CMD} -t "${t}" -A "${c}" -p tcp -d "${ssh_src}" --dport "${ssh_sport}" --sport "${ssh_dport}" -m state --state ESTABLISHED -j ACCEPT
  5103.                 fi
  5104.                 ${IPTABLES_CMD} -t "${t}" -A "${c}" -j DROP
  5105.             done
  5106.         done
  5107.         success $"FireHOL: Blocking all communications:"
  5108.         echo
  5109.         
  5110.         exit 0
  5111.         ;;
  5112.     
  5113.     save)
  5114.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5115.         FIREHOL_TRY=0
  5116.         FIREHOL_SAVE=1
  5117.         ;;
  5118.         
  5119.     debug)
  5120.         test ! -z "${1}" && softwarning "Arguments after parameter '${arg}' are ignored."
  5121.         FIREHOL_TRY=0
  5122.         FIREHOL_DEBUG=1
  5123.         ;;
  5124.     
  5125.     *)    if [ ! -z "${arg}" -a -f "${arg}" ]
  5126.         then
  5127.             FIREHOL_CONFIG="${arg}"
  5128.             arg="${1}"
  5129.             test "${arg}" = "--" && arg="" && shift
  5130.             test -z "${arg}" && arg="try"
  5131.             
  5132.             case "${arg}" in
  5133.                 start)
  5134.                     FIREHOL_TRY=0
  5135.                     FIREHOL_DEBUG=0
  5136.                     ;;
  5137.                     
  5138.                 try)
  5139.                     FIREHOL_TRY=1
  5140.                     FIREHOL_DEBUG=0
  5141.                     ;;
  5142.                     
  5143.                 debug)
  5144.                     FIREHOL_TRY=0
  5145.                     FIREHOL_DEBUG=1
  5146.                     ;;
  5147.                 
  5148.                 *)
  5149.                     echo "Cannot accept command line argument '${arg}' here."
  5150.                     exit 1
  5151.                     ;;
  5152.             esac
  5153.         else
  5154.         
  5155.         ${CAT_CMD} <<EOF
  5156. $Id: firehol.sh,v 1.226 2005/01/25 21:28:19 ktsaou Exp $
  5157. (C) Copyright 2003, Costa Tsaousis <costa@tsaousis.gr>
  5158. FireHOL is distributed under GPL.
  5159.  
  5160. EOF
  5161.  
  5162.         ${CAT_CMD} <<EOF
  5163. FireHOL supports the following command line arguments (only one of them):
  5164.  
  5165.     start        to activate the firewall configuration.
  5166.             The configuration is expected to be found in
  5167.             ${FIREHOL_CONFIG_DIR}/firehol.conf
  5168.             
  5169.     try        to activate the firewall, but wait until
  5170.             the user types the word "commit". If this word
  5171.             is not typed within 30 seconds, the previous
  5172.             firewall is restored.
  5173.             
  5174.     stop        to stop a running iptables firewall.
  5175.             This will allow all traffic to pass unchecked.
  5176.         
  5177.     restart        this is an alias for start and is given for
  5178.             compatibility with /etc/init.d/iptables.
  5179.             
  5180.     condrestart    will start the firewall only if it is not
  5181.             already active. It does not detect a modified
  5182.             configuration file.
  5183.     
  5184.     status        will show the running firewall, as in:
  5185.             ${IPTABLES_CMD} -nxvL | ${LESS_CMD}
  5186.             
  5187.     panic        will block all IP communication.
  5188.     
  5189.     save        to start the firewall and then save it to the
  5190.             place where /etc/init.d/iptables looks for it.
  5191.             
  5192.             Note that not all firewalls will work if
  5193.             restored with:
  5194.             /etc/init.d/iptables start
  5195.             
  5196.     debug        to parse the configuration file but instead of
  5197.             activating it, to show the generated iptables
  5198.             statements.
  5199.     
  5200.     explain        to enter interactive mode and accept configuration
  5201.             directives. It also gives the iptables commands
  5202.             for each directive together with reasoning.
  5203.             
  5204.     helpme    or    to enter a wizard mode where FireHOL will try
  5205.     wizard        to figure out the configuration you need.
  5206.             You can redirect the standard output of FireHOL to
  5207.             a file to get the config to this file.
  5208.             
  5209.     <a filename>    a different configuration file.
  5210.             If not other argument is given, the configuration
  5211.             will be "tried" (default = try).
  5212.             Otherwise the argument next to the filename can
  5213.             be one of 'start', 'debug' and 'try'.
  5214.  
  5215.  
  5216. -------------------------------------------------------------------------
  5217.  
  5218. FireHOL supports the following services (sorted by name):
  5219. EOF
  5220.  
  5221.  
  5222.         (
  5223.             # The simple services
  5224.             ${CAT_CMD} "${me}"                |\
  5225.                 ${GREP_CMD} -e "^server_.*_ports="    |\
  5226.                 ${CUT_CMD} -d '=' -f 1            |\
  5227.                 ${SED_CMD} "s/^server_//"        |\
  5228.                 ${SED_CMD} "s/_ports\$//"
  5229.             
  5230.             # The complex services
  5231.             ${CAT_CMD} "${me}"                |\
  5232.                 ${GREP_CMD} -e "^rules_.*()"        |\
  5233.                 ${CUT_CMD} -d '(' -f 1            |\
  5234.                 ${SED_CMD} "s/^rules_/(*) /"
  5235.         ) | ${SORT_CMD} | ${UNIQ_CMD} |\
  5236.         (
  5237.             x=0
  5238.             while read
  5239.             do
  5240.                 x=$[x + 1]
  5241.                 if [ $x -gt 4 ]
  5242.                 then
  5243.                     printf "\n"
  5244.                     x=1
  5245.                 fi
  5246.                 printf "% 16s |" "$REPLY"
  5247.             done
  5248.             printf "\n\n"
  5249.         )
  5250.         
  5251.         ${CAT_CMD} <<EOF
  5252.  
  5253. Services marked with (*) are "smart" or complex services.
  5254. All the others are simple single socket services.
  5255.  
  5256. Please note that the service:
  5257.     
  5258.     all    matches all packets, all protocols, all of everything,
  5259.         while ensuring that required kernel modules are loaded.
  5260.     
  5261.     any    allows the matching of packets with unusual rules, like
  5262.         only protocol but no ports. If service any is used
  5263.         without other parameters, it does what service all does
  5264.         but it does not handle kernel modules.
  5265.         For example, to match GRE traffic use:
  5266.         
  5267.         server any mygre accept proto 47
  5268.         
  5269.         Service any does not handle kernel modules.
  5270.         
  5271.     custom    allows the definition of a custom service.
  5272.         The template is:
  5273.         
  5274.         server custom name protocol/sport cport accept
  5275.         
  5276.         where name is just a name, protocol is the protocol the
  5277.         service uses (tcp, udp, etc), sport is server port,
  5278.         cport is the client port. For example, IMAP4 is:
  5279.         
  5280.         server custom imap tcp/143 default accept
  5281.  
  5282.  
  5283. For more information about FireHOL, please refer to:
  5284.  
  5285.         http://firehol.sourceforge.net
  5286.  
  5287. -------------------------------------------------------------------------
  5288. FireHOL controls your firewall. You should want to get updates quickly.
  5289. Subscribe (at the home page) to get notified of new releases.
  5290. -------------------------------------------------------------------------
  5291.  
  5292. YOU DO NOT KNOW WHAT TO DO? FireHOL can help you! Just run it with the
  5293. argument 'helpme' and it will generate its configuration file for this
  5294. machine. Your running firewall will not be altered or stopped, and no
  5295. systems settings will be modified. Just run:
  5296.  
  5297. ${FIREHOL_FILE} helpme >/tmp/firehol.conf
  5298.  
  5299. and you will get the configuration written to /tmp/firehol.conf
  5300.  
  5301. EOF
  5302.         exit 1
  5303.         
  5304.         fi
  5305.         ;;
  5306. esac
  5307.  
  5308. # Remove the next arg if it is --
  5309. test "${1}" = "--" && shift
  5310.  
  5311. if [ ${FIREHOL_EXPLAIN} -eq 0 -a ${FIREHOL_WIZARD} -eq 0 -a ! -f "${FIREHOL_CONFIG}" ]
  5312. then
  5313.     echo -n $"FireHOL config ${FIREHOL_CONFIG} not found:"
  5314.     failure $"FireHOL config ${FIREHOL_CONFIG} not found:"
  5315.     echo
  5316.     exit 1
  5317. fi
  5318.  
  5319.  
  5320. # ------------------------------------------------------------------------------
  5321. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  5322. # ------------------------------------------------------------------------------
  5323. #
  5324. # MAIN PROCESSING - Interactive mode
  5325. #
  5326. # ------------------------------------------------------------------------------
  5327. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  5328. # ------------------------------------------------------------------------------
  5329.  
  5330. if [ ${FIREHOL_EXPLAIN} -eq 1 ]
  5331. then
  5332.     FIREHOL_CONFIG="Interactive User Input"
  5333.     FIREHOL_LINEID="1"
  5334.     
  5335.     FIREHOL_TEMP_CONFIG="${FIREHOL_DIR}/firehol.conf"
  5336.     
  5337.     echo "version ${FIREHOL_VERSION}" >"${FIREHOL_TEMP_CONFIG}"
  5338.     version ${FIREHOL_VERSION}
  5339.     
  5340.     ${CAT_CMD} <<EOF
  5341.  
  5342. $Id: firehol.sh,v 1.226 2005/01/25 21:28:19 ktsaou Exp $
  5343. (C) Copyright 2003, Costa Tsaousis <costa@tsaousis.gr>
  5344. FireHOL is distributed under GPL.
  5345. Home Page: http://firehol.sourceforge.net
  5346.  
  5347. --------------------------------------------------------------------------------
  5348. FireHOL controls your firewall. You should want to get updates quickly.
  5349. Subscribe (at the home page) to get notified of new releases.
  5350. --------------------------------------------------------------------------------
  5351.  
  5352. You can now start typing FireHOL configuration directives.
  5353. Special interactive commands: help, show, quit
  5354.  
  5355. EOF
  5356.     
  5357.     while [ 1 = 1 ]
  5358.     do
  5359.         read -p "# FireHOL [${work_cmd}:${work_name}] > " -e -r
  5360.         test -z "${REPLY}" && continue
  5361.         
  5362.         set_work_function -ne "Executing user input"
  5363.         
  5364.         while [ 1 = 1 ]
  5365.         do
  5366.         
  5367.         set -- ${REPLY}
  5368.         
  5369.         case "${1}" in
  5370.             help)
  5371.                 ${CAT_CMD} <<EOF
  5372. You can use anything a FireHOL configuration file accepts, including variables,
  5373. loops, etc. Take only care to write loops in one row.
  5374.  
  5375. Additionaly, you can use the following commands:
  5376.     
  5377.     help    to print this text on your screen.
  5378.     
  5379.     show    to show all the successfull commands so far.
  5380.     
  5381.     quit    to show the interactively given configuration file
  5382.         and quit.
  5383.     
  5384.     in    same as typing: interface eth0 internet
  5385.         This is used as a shortcut to get into the server/client
  5386.         mode in which you can test the rules for certain
  5387.         services.
  5388.  
  5389. EOF
  5390.                 break
  5391.                 ;;
  5392.                 
  5393.             show)
  5394.                 echo
  5395.                 ${CAT_CMD} "${FIREHOL_TEMP_CONFIG}"
  5396.                 echo
  5397.                 break
  5398.                 ;;
  5399.                 
  5400.             quit)
  5401.                 echo
  5402.                 ${CAT_CMD} "${FIREHOL_TEMP_CONFIG}"
  5403.                 echo
  5404.                 exit 1
  5405.                 ;;
  5406.                 
  5407.             in)
  5408.                 REPLY="interface eth0 internet"
  5409.                 continue
  5410.                 ;;
  5411.                 
  5412.             *)
  5413.                 ${CAT_CMD} <<EOF
  5414.  
  5415. # \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
  5416. # Cmd Line : ${FIREHOL_LINEID}
  5417. # Command  : ${REPLY}
  5418. EOF
  5419.                 eval "$@"
  5420.                 if [ $? -gt 0 ]
  5421.                 then
  5422.                     printf "\n# > FAILED <\n"
  5423.                 else
  5424.                     if [ "${1}" = "interface" -o "${1}" = "router" ]
  5425.                     then
  5426.                         echo >>"${FIREHOL_TEMP_CONFIG}"
  5427.                     else
  5428.                         printf "    " >>"${FIREHOL_TEMP_CONFIG}"
  5429.                     fi
  5430.                     
  5431.                     printf "%s\n" "${REPLY}" >>"${FIREHOL_TEMP_CONFIG}"
  5432.                     
  5433.                     FIREHOL_LINEID=$[FIREHOL_LINEID + 1]
  5434.                     
  5435.                     printf "\n# > OK <\n"
  5436.                 fi
  5437.                 break
  5438.                 ;;
  5439.         esac
  5440.         
  5441.         break
  5442.         done
  5443.     done
  5444.     
  5445.     exit 0
  5446. fi
  5447.  
  5448.  
  5449. # ------------------------------------------------------------------------------
  5450. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  5451. # ------------------------------------------------------------------------------
  5452. #
  5453. # MAIN PROCESSING - help wizard
  5454. #
  5455. # ------------------------------------------------------------------------------
  5456. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  5457. # ------------------------------------------------------------------------------
  5458.  
  5459. if [ ${FIREHOL_WIZARD} -eq 1 ]
  5460. then
  5461.     wizard_ask() {
  5462.         local prompt="${1}"; shift
  5463.         local def="${1}"; shift
  5464.         
  5465.         echo
  5466.         
  5467.         while [ 1 = 1 ]
  5468.         do
  5469.             printf >&2 "%s [%s] > " "${prompt}" "${def}"
  5470.             read
  5471.             
  5472.             local ans="${REPLY}"
  5473.             
  5474.             test -z "${ans}" && ans="${def}"
  5475.             
  5476.             local c=0
  5477.             while [ $c -le $# ]
  5478.             do
  5479.                 eval local t="\${${c}}"
  5480.                 
  5481.                 test "${ans}" = "${t}" && break
  5482.                 c=$[c + 1]
  5483.             done
  5484.             
  5485.             test $c -le $# && return $c
  5486.             
  5487.             printf >&2 "*** '${ans}' is not a valid answer. Pick one of "
  5488.             printf >&2 "%s " "$@"
  5489.             echo >&2 
  5490.             echo >&2 
  5491.         done
  5492.         
  5493.         return 0
  5494.     }
  5495.     
  5496.     ip_in_net() {
  5497.         local ip="${1}"; shift
  5498.         local net="${1}"; shift
  5499.         
  5500.         if [ -z "${ip}" -o -z "${net}" ]
  5501.         then
  5502.             return 1
  5503.         fi
  5504.         
  5505.         test "${net}" = "default" && net="0.0.0.0/0"
  5506.         
  5507.         set -- `echo ${ip} | ${TR_CMD} './' '  '`
  5508.         local i1=${1}
  5509.         local i2=${2}
  5510.         local i3=${3}
  5511.         local i4=${4}
  5512.         
  5513.         set -- `echo ${net} | ${TR_CMD} './' '  '`
  5514.         local n1=${1}
  5515.         local n2=${2}
  5516.         local n3=${3}
  5517.         local n4=${4}
  5518.         local n5=${5:-32}
  5519.         
  5520.         local i=$[i1*256*256*256 + i2*256*256 + i3*256 + i4]
  5521.         local n=$[n1*256*256*256 + n2*256*256 + n3*256 + n4]
  5522.         
  5523. #        echo "IP : '${i1}' . '${i2}' . '${i3}' . '${i4}'"
  5524. #        echo "NET: '${n1}' . '${n2}' . '${n3}' . '${n4}' / '${n5}'"
  5525.         
  5526.         local d=1
  5527.         local c=${n5}
  5528.         while [ $c -lt 32 ]
  5529.         do
  5530.             c=$[c + 1]
  5531.             d=$[d * 2]
  5532.         done
  5533.         
  5534.         local nm=$[n + d - 1]
  5535.         
  5536.         printf "### DEBUG: Is ${ip} part of network ${net}? "
  5537.         
  5538.         if [ ${i} -ge ${n} -a ${i} -le ${nm} ]
  5539.         then
  5540.             echo "yes"
  5541.             return 0
  5542.         else
  5543.             echo "no"
  5544.             return 1
  5545.         fi
  5546.     }
  5547.     
  5548.     ip_is_net() {
  5549.         local ip="${1}"; shift
  5550.         local net="${1}"; shift
  5551.         
  5552.         if [ -z "${ip}" -o -z "${net}" ]
  5553.         then
  5554.             return 1
  5555.         fi
  5556.         
  5557.         test "${net}" = "default" && net="0.0.0.0/0"
  5558.         
  5559.         set -- `echo ${ip} | ${TR_CMD} './' '  '`
  5560.         local i1=${1}
  5561.         local i2=${2}
  5562.         local i3=${3}
  5563.         local i4=${4}
  5564.         local i5=${5:-32}
  5565.         
  5566.         set -- `echo ${net} | ${TR_CMD} './' '  '`
  5567.         local n1=${1}
  5568.         local n2=${2}
  5569.         local n3=${3}
  5570.         local n4=${4}
  5571.         local n5=${5:-32}
  5572.         
  5573.         local i=$[i1*256*256*256 + i2*256*256 + i3*256 + i4]
  5574.         local n=$[n1*256*256*256 + n2*256*256 + n3*256 + n4]
  5575.         
  5576.         if [ ${i} -eq ${n} -a ${i5} -eq ${n5} ]
  5577.         then
  5578.             return 0
  5579.         else
  5580.             return 1
  5581.         fi
  5582.     }
  5583.     
  5584.     ip2net() {
  5585.         local ip="${1}"; shift
  5586.         
  5587.         if [ -z "${ip}" ]
  5588.         then
  5589.             return 0
  5590.         fi
  5591.         
  5592.         if [ "${ip}" = "default" ]
  5593.         then
  5594.             echo "default"
  5595.             return 0
  5596.         fi
  5597.         
  5598.         set -- `echo ${ip} | ${TR_CMD} './' '  '`
  5599.         local i1=${1}
  5600.         local i2=${2}
  5601.         local i3=${3}
  5602.         local i4=${4}
  5603.         local i5=${5:-32}
  5604.         
  5605.         echo ${i1}.${i2}.${i3}.${i4}/${i5}
  5606.     }
  5607.     
  5608.     ips2net() {
  5609.         
  5610.         (
  5611.             if [ "A${1}" = "A-" ]
  5612.             then
  5613.                 while read ip
  5614.                 do
  5615.                     ip2net ${ip}
  5616.                 done
  5617.             else
  5618.                 while [ ! -z "${1}" ]
  5619.                 do
  5620.                     ip2net ${1}
  5621.                     shift 
  5622.                 done
  5623.             fi
  5624.         ) | ${SORT_CMD} | ${UNIQ_CMD} | ${TR_CMD} "\n" " "
  5625.     }
  5626.     
  5627.     cd "${FIREHOL_DIR}"
  5628.     "${MKDIR_CMD}" ports
  5629.     "${MKDIR_CMD}" keys
  5630.     cd ports
  5631.     "${MKDIR_CMD}" tcp
  5632.     "${MKDIR_CMD}" udp
  5633.     
  5634.     "${CAT_CMD}" >&2 <<EOF
  5635.  
  5636. $Id: firehol.sh,v 1.226 2005/01/25 21:28:19 ktsaou Exp $
  5637. (C) Copyright 2003, Costa Tsaousis <costa@tsaousis.gr>
  5638. FireHOL is distributed under GPL.
  5639. Home Page: http://firehol.sourceforge.net
  5640.  
  5641. --------------------------------------------------------------------------------
  5642. FireHOL controls your firewall. You should want to get updates quickly.
  5643. Subscribe (at the home page) to get notified of new releases.
  5644. --------------------------------------------------------------------------------
  5645.  
  5646. FireHOL will now try to figure out its configuration file on this system.
  5647. Please have all the services and network interfaces on this system running.
  5648.  
  5649. Your running firewall will not be stopped or altered.
  5650.  
  5651. You can re-run the same command with output redirection to get the config
  5652. to a file. Example:
  5653.  
  5654. EOF
  5655.     echo >&2 "${FIREHOL_FILE} helpme >/tmp/firehol.conf"
  5656.     echo >&2 
  5657.     echo >&2 
  5658.         
  5659.     echo >&2 
  5660.     echo >&2 "Building list of known services."
  5661.     echo >&2 "Please wait..."
  5662.     
  5663.     ${CAT_CMD} /etc/services    |\
  5664.         ${TR_CMD} '\t' ' '    |\
  5665.         ${SED_CMD} "s/ \+/ /g"    >services
  5666.     
  5667.     for c in `echo ${!server_*} | ${TR_CMD} ' ' '\n' | ${GREP_CMD} "_ports$"`
  5668.     do
  5669.         serv=`echo $c | ${SED_CMD} "s/server_//" | ${SED_CMD} "s/_ports//"`
  5670.         
  5671.         eval "ret=\${$c}"
  5672.         for x in ${ret}
  5673.         do
  5674.             proto=`echo $x | ${CUT_CMD} -d '/' -f 1`
  5675.             port=`echo $x | ${CUT_CMD} -d '/' -f 2`
  5676.             
  5677.             test ! -d "${proto}" && continue
  5678.             
  5679.             nport=`${EGREP_CMD} "^${port}[[:space:]][0-9]+/${proto}" services | ${CUT_CMD} -d ' ' -f 2 | ${CUT_CMD} -d '/' -f 1`
  5680.             test -z "${nport}" && nport="${port}"
  5681.             
  5682.             echo "server ${serv}" >"${proto}/${nport}"
  5683.         done
  5684.     done
  5685.     
  5686.     echo "server ftp" >tcp/21
  5687.     echo "server nfs" >udp/2049
  5688.     
  5689.     echo "client amanda" >udp/10080
  5690.     
  5691.     echo "server dhcp" >udp/67
  5692.     echo "server dhcp" >tcp/67
  5693.     
  5694.     echo "client dhcp" >udp/68
  5695.     echo "client dhcp" >tcp/68
  5696.     
  5697.     echo "server emule" >tcp/4662
  5698.     
  5699.     echo "server pptp" >tcp/1723
  5700.     
  5701.     echo "server samba" >udp/137
  5702.     echo "server samba" >udp/138
  5703.     echo "server samba" >tcp/139
  5704.     
  5705.     
  5706.     wizard_ask "Press RETURN to start." "continue" "continue"
  5707.     
  5708.     echo >&2 
  5709.     echo >&2 "--- snip --- snip --- snip --- snip ---"
  5710.     echo >&2 
  5711.     
  5712.     echo "#!${FIREHOL_FILE}"
  5713.     echo "# ------------------------------------------------------------------------------"
  5714.     echo "# This feature is under construction -- use it with care."
  5715.     echo "#             *** NEVER USE THIS CONFIG AS-IS ***"
  5716.     echo "# "
  5717.  
  5718.     ${CAT_CMD} <<EOF
  5719. # $Id: firehol.sh,v 1.226 2005/01/25 21:28:19 ktsaou Exp $
  5720. # (C) Copyright 2003, Costa Tsaousis <costa@tsaousis.gr>
  5721. # FireHOL is distributed under GPL.
  5722. # Home Page: http://firehol.sourceforge.net
  5723. # ------------------------------------------------------------------------------
  5724. # FireHOL controls your firewall. You should want to get updates quickly.
  5725. # Subscribe (at the home page) to get notified of new releases.
  5726. # ------------------------------------------------------------------------------
  5727. #
  5728. EOF
  5729.     echo "# This config will have the same effect as NO PROTECTION!"
  5730.     echo "# Everything that found to be running, is allowed."
  5731.     echo "# "
  5732.     echo "# Date: `${DATE_CMD}` on host `${HOSTNAME_CMD}`"
  5733.     echo "# "
  5734.     echo "# The TODOs bellow, are YOUR to-dos!"
  5735.     echo
  5736.     
  5737.     # globals for routing
  5738.     set -a found_interfaces=
  5739.     set -a found_ips=
  5740.     set -a found_nets=
  5741.     set -a found_excludes=
  5742.     
  5743.     helpme_iface() {
  5744.         local route="${1}"; shift
  5745.         local i="${1}"; shift
  5746.         local iface="${1}"; shift
  5747.         local ifip="${1}"; shift
  5748.         local ifnets="${1}"; shift
  5749.         local ifreason="${1}"; shift
  5750.         
  5751.         # one argument left: ifnets_excluded
  5752.         
  5753.         if [ "${route}" = "route" ]
  5754.         then
  5755.             found_interfaces[$i]="${iface}"
  5756.             found_ips[$i]="${ifip}"
  5757.             found_nets[$i]="${ifnets}"
  5758.             found_excludes[$i]="${1}"
  5759.         fi
  5760.         
  5761.         if [ "${ifnets}" = "default" ]
  5762.         then
  5763.             ifnets="not \"\${UNROUTABLE_IPS} ${1}\""
  5764.         else
  5765.             ifnets="\"${ifnets}\""
  5766.         fi
  5767.         
  5768.         # output the interface
  5769.         echo
  5770.         echo "# Interface No $i."
  5771.         echo "# The purpose of this interface is to control the traffic"
  5772.         if [ ! -z "${ifreason}" ]
  5773.         then
  5774.             echo "# ${ifreason}."
  5775.         else
  5776.             echo "# on the ${iface} interface with IP ${ifip} (net: ${ifnets})."
  5777.         fi
  5778.         echo "# TODO: Change \"interface${i}\" to something with meaning to you."
  5779.         echo "# TODO: Check the optional rule parameters (src/dst)."
  5780.         echo "# TODO: Remove 'dst ${ifip}' if this is dynamically assigned."
  5781.         echo "interface ${iface} interface${i} src ${ifnets} dst ${ifip}"
  5782.         echo
  5783.         echo "    # The default policy is DROP. You can be more polite with REJECT."
  5784.         echo "    # Prefer to be polite on your own clients to prevent timeouts."
  5785.         echo "    policy drop"
  5786.         echo
  5787.         echo "    # If you don't trust the clients behind ${iface} (net ${ifnets}),"
  5788.         echo "    # add something like this."
  5789.         echo "    # > protection strong"
  5790.         echo
  5791.         echo "    # Here are the services listening on ${iface}."
  5792.         echo "    # TODO: Normally, you will have to remove those not needed."
  5793.         
  5794.         (
  5795.             local x=
  5796.             local ports=
  5797.             for x in `${NETSTAT_CMD} -an | ${EGREP_CMD} "^tcp" | ${GREP_CMD} "0.0.0.0:*" | ${EGREP_CMD} " (${ifip}|0.0.0.0):[0-9]+" | ${CUT_CMD} -d ':' -f 2 | ${CUT_CMD} -d ' ' -f 1 | ${SORT_CMD} -n | ${UNIQ_CMD}`
  5798.             do
  5799.                 if [ -f "tcp/${x}" ]
  5800.                 then
  5801.                     echo "    `${CAT_CMD} tcp/${x}` accept"
  5802.                 else
  5803.                     ports="${ports} tcp/${x}"
  5804.                 fi
  5805.             done
  5806.             
  5807.             for x in `${NETSTAT_CMD} -an | ${EGREP_CMD} "^udp" | ${GREP_CMD} "0.0.0.0:*" | ${EGREP_CMD} " (${ifip}|0.0.0.0):[0-9]+" | ${CUT_CMD} -d ':' -f 2 | ${CUT_CMD} -d ' ' -f 1 | ${SORT_CMD} -n | ${UNIQ_CMD}`
  5808.             do
  5809.                 if [ -f "udp/${x}" ]
  5810.                 then
  5811.                     echo "    `${CAT_CMD} udp/${x}` accept"
  5812.                 else
  5813.                     ports="${ports} udp/${x}"
  5814.                 fi
  5815.             done
  5816.             
  5817.             echo "    server ICMP accept"
  5818.             
  5819.             echo "${ports}" | ${TR_CMD} " " "\n" | ${SORT_CMD} -n | ${UNIQ_CMD} | ${TR_CMD} "\n" " " >unknown.ports
  5820.         ) | ${SORT_CMD} | ${UNIQ_CMD}
  5821.         
  5822.         echo
  5823.         echo "    # The following ${iface} server ports are not known by FireHOL:"
  5824.         echo "    # `${CAT_CMD} unknown.ports`"
  5825.         echo "    # TODO: If you need any of them, you should define new services."
  5826.         echo "    #       (see Adding Services at the web site - http://firehol.sf.net)."
  5827.         echo
  5828.         
  5829.         echo "    # The following means that this machine can REQUEST anything via ${iface}."
  5830.         echo "    # TODO: On production servers, avoid this and allow only the"
  5831.         echo "    #       client services you really need."
  5832.         echo "    client all accept"
  5833.         echo
  5834.     }
  5835.     
  5836.     interfaces=`${IP_CMD} link show | ${EGREP_CMD} "^[0-9A-Za-z]+:" | ${CUT_CMD} -d ':' -f 2 | ${SED_CMD} "s/^ //" | ${GREP_CMD} -v "^lo$" | ${SORT_CMD} | ${UNIQ_CMD} | ${TR_CMD} "\n" " "`
  5837.     gw_if=`${IP_CMD} route show | ${GREP_CMD} "^default" | ${SED_CMD} "s/dev /dev:/g" | ${TR_CMD} " " "\n" | ${GREP_CMD} "^dev:" | ${CUT_CMD} -d ':' -f 2`
  5838.     gw_ip=`${IP_CMD} route show | ${GREP_CMD} "^default" | ${SED_CMD} "s/via /via:/g" | ${TR_CMD} " " "\n" | ${GREP_CMD} "^via:" | ${CUT_CMD} -d ':' -f 2 | ips2net -`
  5839.     
  5840.     i=0
  5841.     for iface in ${interfaces}
  5842.     do
  5843.         echo "### DEBUG: Processing interface '${iface}'"
  5844.         ips=`${IP_CMD} addr show dev ${iface} | ${SED_CMD} "s/  / /g" | ${SED_CMD} "s/  / /g" | ${SED_CMD} "s/  / /g" | ${GREP_CMD} "^ inet " | ${CUT_CMD} -d ' ' -f 3 | ${CUT_CMD} -d '/' -f 1 | ips2net -`
  5845.         peer=`${IP_CMD} addr show dev ${iface} | ${SED_CMD} "s/  / /g" | ${SED_CMD} "s/  / /g" | ${SED_CMD} "s/  / /g" | ${SED_CMD} "s/peer /peer:/g" | ${TR_CMD} " " "\n" | ${GREP_CMD} "^peer:" | ${CUT_CMD} -d ':' -f 2 | ips2net -`
  5846.         nets=`${IP_CMD} route show dev ${iface} | ${CUT_CMD} -d ' ' -f 1 | ips2net -`
  5847.         
  5848.         if [ -z "${ips}" -o -z "${nets}" ]
  5849.         then
  5850.             echo
  5851.             echo "# Ignoring interface '${iface}' because does not have an IP or route."
  5852.             echo
  5853.             continue
  5854.         fi
  5855.         
  5856.         for ip in ${ips}
  5857.         do
  5858.             echo "### DEBUG: Processing IP ${ip} of interface '${iface}'"
  5859.             
  5860.             ifreason=""
  5861.             
  5862.             # find all the networks this IP can access directly
  5863.             # or through its peer
  5864.             netcount=0
  5865.             ifnets=
  5866.             ofnets=
  5867.             for net in ${nets}
  5868.             do
  5869.                 test "${net}" = "default" && continue
  5870.                 
  5871.                 found=1
  5872.                 ip_in_net ${ip} ${net}
  5873.                 found=$?
  5874.                 
  5875.                 if [ ${found} -gt 0 -a ! -z "${peer}" ]
  5876.                 then
  5877.                     ip_in_net ${peer} ${net}
  5878.                     found=$?
  5879.                 fi
  5880.                 
  5881.                 if [ ${found} -eq 0 ]
  5882.                 then
  5883.                     # Add it to ifnets
  5884.                     f=0; ff=0
  5885.                     while [ $f -lt $netcount ]
  5886.                     do
  5887.                         if ip_in_net ${net} ${ifnets[$f]}
  5888.                         then
  5889.                             # Already satisfied
  5890.                             ff=1
  5891.                         elif ip_in_net ${ifnets[$f]} ${net}
  5892.                         then
  5893.                             # New one is superset of old
  5894.                             ff=1
  5895.                             ifnets[$f]=${net}
  5896.                         fi
  5897.                         
  5898.                         f=$[f + 1]
  5899.                     done
  5900.                     
  5901.                     if [ $ff -eq 0 ]
  5902.                     then
  5903.                         # Add it
  5904.                         netcount=$[netcount + 1]
  5905.                         ifnets=(${net} ${ifnets[@]})
  5906.                     fi
  5907.                 else
  5908.                     ofnets=(${net} ${ofnets[@]})
  5909.                 fi
  5910.             done
  5911.             
  5912.             # find all the networks this IP can access through gateways
  5913.             if [ ! -z "${ofnets[*]}" ]
  5914.             then
  5915.                 for net in ${ofnets[@]}
  5916.                 do
  5917.                     test "${net}" = "default" && continue
  5918.                     
  5919.                     nn=`echo "${net}" | ${CUT_CMD} -d "/" -f 1`
  5920.                     gw=`${IP_CMD} route show ${nn} dev ${iface} | ${EGREP_CMD} "^${nn}[[:space:]]+via[[:space:]][0-9\.]+" | ${CUT_CMD} -d ' ' -f 3 | ips2net -`
  5921.                     test -z "${gw}" && continue
  5922.                     
  5923.                     for nn in ${ifnets[@]}
  5924.                     do
  5925.                         test "${nn}" = "default" && continue
  5926.                         
  5927.                         if ip_in_net ${gw} ${nn}
  5928.                         then
  5929.                             echo "### DEBUG: Route ${net} is accessed through ${gw}"
  5930.                             
  5931.                             # Add it to ifnets
  5932.                             f=0; ff=0
  5933.                             while [ $f -lt $netcount ]
  5934.                             do
  5935.                                 if ip_in_net ${net} ${ifnets[$f]}
  5936.                                 then
  5937.                                     # Already satisfied
  5938.                                     ff=1
  5939.                                 elif ip_in_net ${ifnets[$f]} ${net}
  5940.                                 then
  5941.                                     # New one is superset of old
  5942.                                     ff=1
  5943.                                     ifnets[$f]=${net}
  5944.                                 fi
  5945.                                 
  5946.                                 f=$[f + 1]
  5947.                             done
  5948.                             
  5949.                             if [ $ff -eq 0 ]
  5950.                             then
  5951.                                 # Add it
  5952.                                 netcount=$[netcount + 1]
  5953.                                 ifnets=(${net} ${ifnets[@]})
  5954.                             fi
  5955.                             break
  5956.                         fi
  5957.                     done
  5958.                 done
  5959.             fi
  5960.             
  5961.             # Don't produce an interface if this is just a peer that is also the default gw
  5962.             def_ignore_ifnets=0
  5963.             if (test ${netcount} -eq 1 -a "${gw_if}" = "${iface}" && ip_is_net "${peer}" "${ifnets[*]}" && ip_is_net "${gw_ip}" "${peer}")
  5964.             then
  5965.                 echo "### DEBUG: Skipping ${iface} peer ${ifnets[*]} only interface (default gateway)."
  5966.                 echo
  5967.                 def_ignore_ifnets=1
  5968.             else
  5969.                 i=$[i + 1]
  5970.                 helpme_iface route $i "${iface}" "${ip}" "${ifnets[*]}" "${ifreason}"
  5971.             fi
  5972.             
  5973.             # Is this interface the default gateway too?
  5974.             if [ "${gw_if}" = "${iface}" ]
  5975.             then
  5976.                 for nn in ${ifnets[@]}
  5977.                 do
  5978.                     if ip_in_net "${gw_ip}" ${nn}
  5979.                     then
  5980.                         echo "### DEBUG: Default gateway ${gw_ip} is part of network ${nn}"
  5981.                         
  5982.                         i=$[i + 1]
  5983.                         helpme_iface route $i "${iface}" "${ip}" "default" "from/to unknown networks behind the default gateway ${gw_ip}" "`test ${def_ignore_ifnets} -eq 0 && echo "${ifnets[*]}"`"
  5984.                         
  5985.                         break
  5986.                     fi
  5987.                 done
  5988.             fi
  5989.         done
  5990.     done
  5991.         
  5992.     echo
  5993.     echo "# The above $i interfaces were found active at this moment."
  5994.     echo "# Add more interfaces that can potentially be activated in the future."
  5995.     echo "# FireHOL will not complain if you setup a firewall on an interface that is"
  5996.     echo "# not active when you activate the firewall."
  5997.     echo "# If you don't setup an interface, FireHOL will drop all traffic from or to"
  5998.     echo "# this interface, if and when it becomes available."
  5999.     echo "# Also, if an interface name dynamically changes (i.e. ppp0 may become ppp1)"
  6000.     echo "# you can use the plus (+) character to match all of them (i.e. ppp+)."
  6001.     echo
  6002.     
  6003.     if [ "1" = "`${CAT_CMD} /proc/sys/net/ipv4/ip_forward`" ]
  6004.     then
  6005.         x=0
  6006.         i=0
  6007.         while [ $i -lt ${#found_interfaces[*]} ]
  6008.         do
  6009.             i=$[i + 1]
  6010.             
  6011.             inface="${found_interfaces[$i]}"
  6012.             src="${found_nets[$i]}"
  6013.             
  6014.             case "${src}" in
  6015.                 "default")
  6016.                     src="not \"\${UNROUTABLE_IPS} ${found_excludes[$i]}\""
  6017.                     ;;
  6018.                     
  6019.                     *)
  6020.                     src="\"${src}\""
  6021.                     ;;
  6022.             esac
  6023.             
  6024.             j=0
  6025.             while [ $j -lt ${#found_interfaces[*]} ]
  6026.             do
  6027.                 j=$[j + 1]
  6028.                 
  6029.                 test $j -eq $i && continue
  6030.                 
  6031.                 outface="${found_interfaces[$j]}"
  6032.                 dst="${found_nets[$j]}"
  6033.                 dst_ip="${found_ips[$j]}"
  6034.                 
  6035.                 case "${dst}" in
  6036.                     "default")
  6037.                         dst="not \"\${UNROUTABLE_IPS} ${found_excludes[$j]}\""
  6038.                         ;;
  6039.                         
  6040.                         *)
  6041.                         dst="\"${dst}\""
  6042.                         ;;
  6043.                 esac
  6044.                 
  6045.                 # Make sure we are not routing to the same subnet
  6046.                 test "${inface}" = "${outface}" -a "${src}" = "${dst}" && continue
  6047.                 
  6048.                 # Make sure this is not a duplicate router
  6049.                 key="`echo ${inface}/${src}-${outface}/${dst} | ${TR_CMD} "/ \\\$\\\"{}" "______"`"
  6050.                 test -f "${FIREHOL_DIR}/keys/${key}" && continue
  6051.                 ${TOUCH_CMD} "${FIREHOL_DIR}/keys/${key}"
  6052.                 
  6053.                 x=$[x + 1]
  6054.                 
  6055.                 echo
  6056.                 echo "# Router No ${x}."
  6057.                 echo "# Clients on ${inface} (from ${src}) accessing servers on ${outface} (to ${dst})."
  6058.                 echo "# TODO: Change \"router${x}\" to something with meaning to you."
  6059.                 echo "# TODO: Check the optional rule parameters (src/dst)."
  6060.                 echo "router router${x} inface ${inface} outface ${outface} src ${src} dst ${dst}"
  6061.                 echo 
  6062.                 echo "    # If you don't trust the clients on ${inface} (from ${src}), or"
  6063.                 echo "    # if you want to protect the servers on ${outface} (to ${dst}),"
  6064.                 echo "    # uncomment the following line."
  6065.                 echo "    # > protection strong"
  6066.                 echo
  6067.                 echo "    # To NAT client requests on the output of ${outface}, add this."
  6068.                 echo "    # > masquerade"
  6069.                 
  6070.                 echo "    # Alternatively, you can SNAT them by placing this at the top of this config:"
  6071.                 echo "    # > snat to ${dst_ip} outface ${outface} src ${src} dst ${dst}"
  6072.                 echo "    # SNAT commands can be enhanced using 'proto', 'sport', 'dport', etc in order to"
  6073.                 echo "    # NAT only some specific traffic."
  6074.                 echo
  6075.                 echo "    # TODO: This will allow all traffic to pass."
  6076.                 echo "    # If you remove it, no REQUEST will pass matching this traffic."
  6077.                 echo "    route all accept"
  6078.                 echo
  6079.             done
  6080.         done
  6081.         
  6082.         if [ ${x} -eq 0 ]
  6083.         then
  6084.             echo
  6085.             echo
  6086.             echo "# No router statements have been produced, because your server"
  6087.             echo "# does not seem to need any."
  6088.             echo
  6089.         fi
  6090.     else
  6091.         echo
  6092.         echo
  6093.         echo "# No router statements have been produced, because your server"
  6094.         echo "# is not configured for forwarding traffic."
  6095.         echo
  6096.     fi
  6097.     
  6098.     exit 0
  6099. fi
  6100.  
  6101. # ------------------------------------------------------------------------------
  6102. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6103. # ------------------------------------------------------------------------------
  6104. #
  6105. # MAIN PROCESSING
  6106. #
  6107. # ------------------------------------------------------------------------------
  6108. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6109. # ------------------------------------------------------------------------------
  6110.  
  6111. # --- Initialization -----------------------------------------------------------
  6112.  
  6113. fixed_iptables_save() {
  6114.     local tmp="${FIREHOL_DIR}/iptables-save-$$"
  6115.     local err=
  6116.     
  6117.     load_kernel_module ip_tables
  6118.     ${IPTABLES_SAVE_CMD} -c >$tmp
  6119.     err=$?
  6120.     if [ ! $err -eq 0 ]
  6121.     then
  6122.         ${RM_CMD} -f $tmp >/dev/null 2>&1
  6123.         return $err
  6124.     fi
  6125.     
  6126.     ${CAT_CMD} ${tmp} |\
  6127.         ${SED_CMD} "s/--uid-owner !/! --uid-owner /g"    |\
  6128.         ${SED_CMD} "s/--gid-owner !/! --gid-owner /g"    |\
  6129.         ${SED_CMD} "s/--pid-owner !/! --pid-owner /g"    |\
  6130.         ${SED_CMD} "s/--sid-owner !/! --sid-owner /g"    |\
  6131.         ${SED_CMD} "s/--cmd-owner !/! --cmd-owner /g"
  6132.     
  6133.     err=$?
  6134.     
  6135.     ${RM_CMD} -f $tmp >/dev/null 2>&1
  6136.     return $err
  6137. }
  6138.  
  6139. echo -n $"FireHOL: Saving your old firewall to a temporary file:"
  6140. fixed_iptables_save >${FIREHOL_SAVED}
  6141. if [ $? -eq 0 ]
  6142. then
  6143.     success $"FireHOL: Saving your old firewall to a temporary file:"
  6144.     echo
  6145. else
  6146.     test -f "${FIREHOL_SAVED}" && ${RM_CMD} -f "${FIREHOL_SAVED}"
  6147.     failure $"FireHOL: Saving your old firewall to a temporary file:"
  6148.     echo
  6149.     exit 1
  6150. fi
  6151.  
  6152.  
  6153. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6154.  
  6155. # Place all the statements bellow to the beginning of the final firewall script.
  6156. ${CAT_CMD} >"${FIREHOL_OUTPUT}" <<EOF
  6157. #!/bin/sh
  6158.  
  6159. load_kernel_module ip_tables
  6160. load_kernel_module ip_conntrack
  6161.  
  6162. # Find all tables supported
  6163. tables=\`${CAT_CMD} /proc/net/ip_tables_names\`
  6164. for t in \${tables}
  6165. do
  6166.     # Reset/empty this table.
  6167.     ${IPTABLES_CMD} -t "\${t}" -F >${FIREHOL_OUTPUT}.log 2>&1
  6168.     r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t "\${t}" -F
  6169.     
  6170.     ${IPTABLES_CMD} -t "\${t}" -X >${FIREHOL_OUTPUT}.log 2>&1
  6171.     r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t "\${t}" -X
  6172.     
  6173.     ${IPTABLES_CMD} -t "\${t}" -Z >${FIREHOL_OUTPUT}.log 2>&1
  6174.     r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t "\${t}" -Z
  6175.     
  6176.     # Find all default chains in this table.
  6177.     chains=\`${IPTABLES_CMD} -t "\${t}" -nL | ${GREP_CMD} "^Chain " | ${CUT_CMD} -d ' ' -f 2\`
  6178.     
  6179.     # If this is the 'filter' table, remember the default chains.
  6180.     # This will be used at the end to make it DROP all packets.
  6181.     test "\${t}" = "filter" && firehol_filter_chains="\${chains}"
  6182.     
  6183.     # Set the policy to ACCEPT on all default chains.
  6184.     for c in \${chains}
  6185.     do
  6186.         ${IPTABLES_CMD} -t "\${t}" -P "\${c}" ACCEPT >${FIREHOL_OUTPUT}.log 2>&1
  6187.         r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t "\${t}" -P "\${c}" ACCEPT
  6188.     done
  6189. done
  6190.  
  6191. ${IPTABLES_CMD} -t filter -P INPUT "\${FIREHOL_INPUT_ACTIVATION_POLICY}" >${FIREHOL_OUTPUT}.log 2>&1
  6192. r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t filter -P INPUT "\${FIREHOL_INPUT_ACTIVATION_POLICY}"
  6193.  
  6194. ${IPTABLES_CMD} -t filter -P OUTPUT "\${FIREHOL_OUTPUT_ACTIVATION_POLICY}" >${FIREHOL_OUTPUT}.log 2>&1
  6195. r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t filter -P OUTPUT "\${FIREHOL_OUTPUT_ACTIVATION_POLICY}"
  6196.  
  6197. ${IPTABLES_CMD} -t filter -P FORWARD "\${FIREHOL_FORWARD_ACTIVATION_POLICY}" >${FIREHOL_OUTPUT}.log 2>&1
  6198. r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t filter -P FORWARD "\${FIREHOL_FORWARD_ACTIVATION_POLICY}"
  6199.  
  6200. # Accept everything in/out the loopback device.
  6201. if [ "\${FIREHOL_TRUST_LOOPBACK}" = "1" ]
  6202. then
  6203.     ${IPTABLES_CMD} -A INPUT -i lo -j ACCEPT
  6204.     ${IPTABLES_CMD} -A OUTPUT -o lo -j ACCEPT
  6205. fi
  6206.  
  6207. # Drop all invalid packets.
  6208. # Netfilter HOWTO suggests to DROP all INVALID packets.
  6209. if [ "\${FIREHOL_DROP_INVALID}" = "1" ]
  6210. then
  6211.     ${IPTABLES_CMD} -A INPUT -m state --state INVALID -j DROP
  6212.     ${IPTABLES_CMD} -A OUTPUT -m state --state INVALID -j DROP
  6213.     ${IPTABLES_CMD} -A FORWARD -m state --state INVALID -j DROP
  6214. fi
  6215.  
  6216. EOF
  6217.  
  6218. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6219.  
  6220. echo -n $"FireHOL: Processing file ${FIREHOL_CONFIG}:"
  6221. ret=0
  6222.  
  6223. # ------------------------------------------------------------------------------
  6224. # Create a small awk script that inserts line numbers in the configuration file
  6225. # just before each known directive.
  6226. # These line numbers will be used for debugging the configuration script.
  6227.  
  6228. ${CAT_CMD} >"${FIREHOL_TMP}.awk" <<"EOF"
  6229. /^[[:space:]]*blacklist[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6230. /^[[:space:]]*client[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6231. /^[[:space:]]*dnat[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6232. /^[[:space:]]*dscp[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6233. /^[[:space:]]*interface[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6234. /^[[:space:]]*iptables[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6235. /^[[:space:]]*mac[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6236. /^[[:space:]]*mark[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6237. /^[[:space:]]*masquerade[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6238. /^[[:space:]]*nat[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6239. /^[[:space:]]*policy[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6240. /^[[:space:]]*postprocess[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6241. /^[[:space:]]*protection[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6242. /^[[:space:]]*redirect[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6243. /^[[:space:]]*router[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6244. /^[[:space:]]*route[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6245. /^[[:space:]]*server[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6246. /^[[:space:]]*snat[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6247. /^[[:space:]]*tcpmss[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6248. /^[[:space:]]*tos[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6249. /^[[:space:]]*transparent_squid[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6250. /^[[:space:]]*transparent_proxy[[:space:]]/ { printf "FIREHOL_LINEID=${LINENO} " }
  6251. { print }
  6252. EOF
  6253.  
  6254. ${CAT_CMD} ${FIREHOL_CONFIG} | ${GAWK_CMD} -f "${FIREHOL_TMP}.awk" >${FIREHOL_TMP}
  6255. ${RM_CMD} -f "${FIREHOL_TMP}.awk"
  6256.  
  6257. # ------------------------------------------------------------------------------
  6258. # Run the configuration file.
  6259.  
  6260. enable -n trap            # Disable the trap buildin shell command.
  6261. enable -n exit            # Disable the exit buildin shell command.
  6262. source ${FIREHOL_TMP} "$@"    # Run the configuration as a normal script.
  6263. FIREHOL_LINEID="FIN"
  6264. enable trap            # Enable the trap buildin shell command.
  6265. enable exit            # Enable the exit buildin shell command.
  6266.  
  6267.  
  6268. close_cmd                    || ret=$[ret + 1]
  6269. close_master                    || ret=$[ret + 1]
  6270.  
  6271. ${CAT_CMD} >>"${FIREHOL_OUTPUT}" <<EOF
  6272.  
  6273. # Make it drop everything on table 'filter'.
  6274. for c in \${firehol_filter_chains}
  6275. do
  6276.     ${IPTABLES_CMD} -t filter -P "\${c}" DROP >${FIREHOL_OUTPUT}.log 2>&1
  6277.     r=\$?; test ! \${r} -eq 0 && runtime_error error \${r} INIT ${IPTABLES_CMD} -t filter -P "\${c}" DROP
  6278. done
  6279.  
  6280. EOF
  6281.  
  6282. if [ ${work_error} -gt 0 -o $ret -gt 0 ]
  6283. then
  6284.     echo >&2
  6285.     echo >&2 "NOTICE: No changes made to your firewall."
  6286.     failure $"FireHOL: Processing file ${FIREHOL_CONFIG}:"
  6287.     echo
  6288.     exit 1
  6289. fi
  6290.  
  6291. success $"FireHOL: Processing file ${FIREHOL_CONFIG}:"
  6292. echo
  6293.  
  6294.  
  6295. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6296.  
  6297. for m in ${FIREHOL_KERNEL_MODULES}
  6298. do
  6299.     postprocess -ne load_kernel_module $m
  6300. done
  6301.  
  6302. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6303.  
  6304. if [ $FIREHOL_ROUTING -eq 1 ]
  6305. then
  6306.     postprocess ${SYSCTL_CMD} -w "net.ipv4.ip_forward=1"
  6307. fi
  6308.  
  6309. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6310.  
  6311. if [ ${FIREHOL_DEBUG} -eq 1 ]
  6312. then
  6313.     ${CAT_CMD} ${FIREHOL_OUTPUT}
  6314.     
  6315.     exit 1
  6316. fi
  6317.  
  6318.  
  6319. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6320.  
  6321. echo -n $"FireHOL: Activating new firewall (${FIREHOL_COMMAND_COUNTER} rules):"
  6322.  
  6323. source ${FIREHOL_OUTPUT} "$@"
  6324.  
  6325. if [ ${work_final_status} -gt 0 ]
  6326. then
  6327.     failure $"FireHOL: Activating new firewall:"
  6328.     echo
  6329.     
  6330.     # The trap will restore the firewall.
  6331.     
  6332.     exit 1
  6333. fi
  6334. success $"FireHOL: Activating new firewall (${FIREHOL_COMMAND_COUNTER} rules):"
  6335. echo
  6336.  
  6337. if [ ${FIREHOL_TRY} -eq 1 ]
  6338. then
  6339.     read -p "Keep the firewall? (type 'commit' to accept - 30 seconds timeout) : " -t 30 -e
  6340.     ret=$?
  6341.     echo
  6342.     if [ ! $ret -eq 0 -o ! "${REPLY}" = "commit" ]
  6343.     then
  6344.         # The trap will restore the firewall.
  6345.         
  6346.         exit 1
  6347.     else
  6348.         echo "Successfull activation of FireHOL firewall."
  6349.     fi
  6350. fi
  6351.  
  6352. # Remove the saved firewall, so that the trap will not restore it.
  6353. ${RM_CMD} -f "${FIREHOL_SAVED}"
  6354.  
  6355. # RedHat startup service locking.
  6356. if [ -d /var/lock/subsys ]
  6357. then
  6358.     ${TOUCH_CMD} /var/lock/subsys/iptables
  6359.     ${TOUCH_CMD} /var/lock/subsys/firehol
  6360. fi
  6361.  
  6362.  
  6363. # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  6364.  
  6365. if [ ${FIREHOL_SAVE} -eq 1 ]
  6366. then
  6367.     if [ -z "${FIREHOL_AUTOSAVE}" ]
  6368.     then
  6369.         if [ -d "/etc/sysconfig" ]
  6370.         then
  6371.             # RedHat
  6372.             FIREHOL_AUTOSAVE="/etc/sysconfig/iptables"
  6373.         elif [ -d "/var/lib/iptables" ]
  6374.         then
  6375.             if [ -f /etc/conf.d/iptables ]
  6376.             then
  6377.                 # Gentoo
  6378.                 IPTABLES_SAVE=
  6379.                 
  6380.                 . /etc/conf.d/iptables
  6381.                 FIREHOL_AUTOSAVE="${IPTABLES_SAVE}"
  6382.             fi
  6383.             
  6384.             if [ -z "${FIREHOL_AUTOSAVE}" ]
  6385.             then
  6386.                 # Debian
  6387.                 FIREHOL_AUTOSAVE="/var/lib/iptables/autosave"
  6388.             fi
  6389.         else
  6390.             error "Cannot find where to save iptables file. Please set FIREHOL_AUTOSAVE."
  6391.             echo
  6392.             exit 1
  6393.         fi
  6394.     fi
  6395.     
  6396.     echo -n $"FireHOL: Saving firewall to ${FIREHOL_AUTOSAVE}:"
  6397.     
  6398.     fixed_iptables_save >"${FIREHOL_AUTOSAVE}"
  6399.     
  6400.     if [ ! $? -eq 0 ]
  6401.     then
  6402.         failure $"FireHOL: Saving firewall to ${FIREHOL_AUTOSAVE}:"
  6403.         echo
  6404.         exit 1
  6405.     fi
  6406.     
  6407.     success $"FireHOL: Saving firewall to ${FIREHOL_AUTOSAVE}:"
  6408.     echo
  6409.     exit 0
  6410. fi
  6411.